Beispiel #1
0
void
list_publics(int descr, dbref player, int arg[], int argc)
{
	dbref program;

	if (argc > 1) {
		notify(player,
			   "I don't understand which program you want to list PUBLIC functions for.");
		return;
	}
	program = (argc == 0) ? PLAYER_CURR_PROG(player) : arg[0];
	if (Typeof(program) != TYPE_PROGRAM) {
		notify(player, "That isn't a program.");
		return;
	}
	if (!(controls(player, program) || Linkable(program))) {
		notify(player, "That's not a public program.");
		return;
	}
	if (!(PROGRAM_CODE(program))) {
		if (program == PLAYER_CURR_PROG(player)) {
			do_compile(descr, OWNER(program), program, 0);
		} else {
			struct line *tmpline;

			tmpline = PROGRAM_FIRST(program);
			PROGRAM_SET_FIRST(program, (struct line *) read_program(program));
			do_compile(descr, OWNER(program), program, 0);
			free_prog_text(PROGRAM_FIRST(program));
			PROGRAM_SET_FIRST(program, tmpline);
		}
		if (!PROGRAM_CODE(program)) {
			notify(player, "Program not compilable.");
			return;
		}
	}
	do_list_publics(player, program);
}
Beispiel #2
0
void
prim_cancallp(PRIM_PROTOTYPE)
{
    CHECKOP(2);
    oper2 = POP();		/* string: public function name */
    oper1 = POP();		/* dbref: Program dbref to check */
    if (oper1->type != PROG_OBJECT)
	abort_interp("Expected dbref argument. (1)");
    if (!valid_object(oper1))
	abort_interp("Invalid dbref (1)");
    if (Typeof(oper1->data.objref) != TYPE_PROGRAM)
	abort_interp("Object is not a MUF Program. (1)");
    if (oper2->type != PROG_STRING)
	abort_interp("Expected string argument. (2)");
    if (!oper2->data.string)
	abort_interp("Invalid Null string argument. (2)");

    if (!(PROGRAM_CODE(oper1->data.objref))) {
	struct line *tmpline;

	tmpline = PROGRAM_FIRST(oper1->data.objref);
	PROGRAM_SET_FIRST(oper1->data.objref,
			  (struct line *) read_program(oper1->data.objref));
	do_compile(-1, OWNER(oper1->data.objref), oper1->data.objref, 0);
	free_prog_text(PROGRAM_FIRST(oper1->data.objref));
	PROGRAM_SET_FIRST(oper1->data.objref, tmpline);
    }

    result = 0;
    if (ProgMLevel(oper1->data.objref) > 0 &&
	(mlev >= 4 || OWNER(oper1->data.objref) == ProgUID || Linkable(oper1->data.objref))
	    ) {
	struct publics *pbs;

	pbs = PROGRAM_PUBS(oper1->data.objref);
	while (pbs) {
	    if (!strcasecmp(oper2->data.string->data, pbs->subname))
		break;
	    pbs = pbs->next;
	}
	if (pbs && mlev >= pbs->mlev)
	    result = 1;
    }
    CHECKOFLOW(1);
    CLEAR(oper1);
    CLEAR(oper2);
    PushInt(result);
}
Beispiel #3
0
/**
 * Convert a line number to an instruction pointer
 *
 * @private
 * @param program dbref
 * @param whatline the line to find an instruction pointer for
 * @return pointer to starting instruction for the given line
 */
static struct inst *
linenum_to_pc(dbref program, int whatline)
{
    int siz;
    struct inst *code;

    code = PROGRAM_CODE(program);
    siz = PROGRAM_SIZ(program);

    for (int i = 0; i < siz; i++) {
        if (code[i].line == whatline) {
            return (code + i);
        }
    }

    return (NULL);
}
Beispiel #4
0
/**
 * Convert a function name to an instruction pointer
 *
 * @private
 * @param program the program dbref
 * @param name the procedure name to look for
 * @return pointer to start of procedure
 */
static struct inst *
funcname_to_pc(dbref program, const char *name)
{
    int siz;
    struct inst *code;

    code = PROGRAM_CODE(program);
    siz = PROGRAM_SIZ(program);

    for (int i = 0; i < siz; i++) {
        if ((code[i].type == PROG_FUNCTION) &&
            !strcasecmp(name, code[i].data.mufproc->procname)) {
            return (code + i);
        }
    }

    return (NULL);
}
Beispiel #5
0
/**
 * Figures out the name of the current function for the given program counter
 *
 * It is functions like this why the documentation project is a thing.
 * Kind of undescriptive (even misleading) name, somewhat cryptic code.
 *
 * This 'rewinds' the code from the given pc location until it figures
 * out which function 'pc' lives in and returns a static buffer containing
 * pc's line number and containing function name information.
 *
 * Note that because this is a static buffer, you must be careful with
 * it; it is not thread-safe and it can theoretically mutate if you
 * hold onto the pointer for some reason.
 *
 * @private
 * @param program the dbref of the program
 * @param pc the program counter
 * @return a descriptive string with pc line number and function name
 */
static char *
unparse_sysreturn(dbref * program, struct inst *pc)
{
    static char buf[BUFFER_LEN];
    struct inst *ptr;
    char *fname;

    buf[0] = '\0';
    for (ptr = pc; ptr >= PROGRAM_CODE(*program); ptr--) {
        if (ptr->type == PROG_FUNCTION) {
            break;
        }
    }

    if (ptr->type == PROG_FUNCTION) {
        fname = ptr->data.mufproc->procname;
    } else {
        fname = "\033[1m???\033[0m";
    }

    snprintf(buf, sizeof(buf), "line \033[1m%d\033[0m, in \033[1m%s\033[0m", pc->line, fname);
    return buf;
}
Beispiel #6
0
/**
 * List the functions in a program
 *
 * Optionally provide a filter string that will match functions using
 * equalstr
 *
 * @see equalstr
 *
 * You cannot pass NULL into arg, you can pass empty string if you wish to
 * show all functions.
 *
 * @private
 * @param player the person to show the list of functions to
 * @param program the program to list functions from
 * @param arg a filter string or ""
 */
static void
list_program_functions(dbref player, dbref program, char *arg)
{
    struct inst *ptr;
    int count;

    ptr = PROGRAM_CODE(program);
    count = PROGRAM_SIZ(program);
    notify_nolisten(player, "*function words*", 1);

    while (count-- > 0) {
        if (ptr->type == PROG_FUNCTION) {
            if (ptr->data.mufproc) {
                if (!*arg || equalstr(arg, ptr->data.mufproc->procname)) {
                    notify_nolisten(player, ptr->data.mufproc->procname, 1);
                }
            }
        }

        ptr++;
    }

    notify_nolisten(player, "*done*", 1);
}
Beispiel #7
0
struct frame *
interp(int descr, dbref player, dbref location, dbref program,
	   dbref source, int nosleeps, int whichperms, int forced_pid)
{
	struct frame *fr;
	int i;

	if (!MLevel(program) || !MLevel(OWNER(program)) ||
		((source != NOTHING) && !TrueWizard(OWNER(source)) &&
		 !can_link_to(OWNER(source), TYPE_EXIT, program))) {
		notify_nolisten(player, "Program call: Permission denied.", 1);
		return 0;
	}
	if (free_frames_list) {
		fr = free_frames_list;
		free_frames_list = fr->next;
	} else {
		fr = (struct frame *) malloc(sizeof(struct frame));
	}
	fr->next = NULL;
	fr->pid = forced_pid ? forced_pid : top_pid++;
	fr->descr = descr;
	fr->multitask = nosleeps;
	fr->perms = whichperms;
	fr->already_created = 0;
	fr->been_background = (nosleeps == 2);
	fr->trig = source;
	fr->events = NULL;
	fr->timercount = 0;
	fr->started = time(NULL);
	fr->instcnt = 0;
	fr->skip_declare = 0;
	fr->wantsblanks = 0;
	fr->caller.top = 1;
	fr->caller.st[0] = source;
	fr->caller.st[1] = program;

	fr->system.top = 1;
	fr->system.st[0].progref = 0;
	fr->system.st[0].offset = 0;

	fr->waitees = NULL;
	fr->waiters = NULL;

	fr->fors.top = 0;
	fr->fors.st = NULL;
	fr->trys.top = 0;
	fr->trys.st = NULL;

	fr->errorstr = NULL;
	fr->errorinst = NULL;
	fr->errorprog = NOTHING;
	fr->errorline = 0;

	fr->rndbuf = NULL;
	fr->dlogids = NULL;

	fr->argument.top = 0;
	fr->pc = PROGRAM_START(program);
	fr->writeonly = ((source == -1) || (Typeof(source) == TYPE_ROOM) ||
					 ((Typeof(source) == TYPE_PLAYER) && (!online(source))) ||
					 (FLAGS(player) & READMODE));
	fr->level = 0;
	fr->error.is_flags = 0;

	/* set basic local variables */

	fr->svars = NULL;
	fr->lvars = NULL;
	for (i = 0; i < MAX_VAR; i++) {
		fr->variables[i].type = PROG_INTEGER;
		fr->variables[i].data.number = 0;
	}

	fr->brkpt.force_debugging = 0;
	fr->brkpt.debugging = 0;
	fr->brkpt.bypass = 0;
	fr->brkpt.isread = 0;
	fr->brkpt.showstack = 0;
	fr->brkpt.dosyspop = 0;
	fr->brkpt.lastline = 0;
	fr->brkpt.lastpc = 0;
	fr->brkpt.lastlisted = 0;
	fr->brkpt.lastcmd = NULL;
	fr->brkpt.breaknum = -1;

	fr->brkpt.lastproglisted = NOTHING;
	fr->brkpt.proglines = NULL;

	fr->brkpt.count = 1;
	fr->brkpt.temp[0] = 1;
	fr->brkpt.level[0] = -1;
	fr->brkpt.line[0] = -1;
	fr->brkpt.linecount[0] = -2;
	fr->brkpt.pc[0] = NULL;
	fr->brkpt.pccount[0] = -2;
	fr->brkpt.prog[0] = program;

	fr->proftime.tv_sec = 0;
	fr->proftime.tv_usec = 0;
	fr->totaltime.tv_sec = 0;
	fr->totaltime.tv_usec = 0;

	fr->variables[0].type = PROG_OBJECT;
	fr->variables[0].data.objref = player;
	fr->variables[1].type = PROG_OBJECT;
	fr->variables[1].data.objref = location;
	fr->variables[2].type = PROG_OBJECT;
	fr->variables[2].data.objref = source;
	fr->variables[3].type = PROG_STRING;
	fr->variables[3].data.string = (!*match_cmdname) ? 0 : alloc_prog_string(match_cmdname);

	if (PROGRAM_CODE(program)) {
		PROGRAM_INC_PROF_USES(program);
	}
	PROGRAM_INC_INSTANCES(program);
	push(fr->argument.st, &(fr->argument.top), PROG_STRING, *match_args ?
		 MIPSCAST alloc_prog_string(match_args) : 0);
	return fr;
}
Beispiel #8
0
struct inst *
interp_loop(dbref player, dbref program, struct frame *fr, int rettyp)
{
	register struct inst *pc;
	register int atop;
	register struct inst *arg;
	register struct inst *temp1;
	register struct inst *temp2;
	register struct stack_addr *sys;
	register int instr_count;
	register int stop;
	int i = 0, tmp, writeonly, mlev;
	static struct inst retval;
	char dbuf[BUFFER_LEN];
	int instno_debug_line = get_primitive("debug_line");


	fr->level = ++interp_depth;	/* increment interp level */

	/* load everything into local stuff */
	pc = fr->pc;
	atop = fr->argument.top;
	stop = fr->system.top;
	arg = fr->argument.st;
	sys = fr->system.st;
	writeonly = fr->writeonly;
	already_created = 0;
	fr->brkpt.isread = 0;

	if (!pc) {
		struct line *tmpline;

		tmpline = PROGRAM_FIRST(program);
		PROGRAM_SET_FIRST(program, (struct line *) read_program(program));
		do_compile(-1, OWNER(program), program, 0);
		free_prog_text(PROGRAM_FIRST(program));
		PROGRAM_SET_FIRST(program, tmpline);
		pc = fr->pc = PROGRAM_START(program);
		if (!pc) {
			abort_loop_hard("Program not compilable. Cannot run.", NULL, NULL);
		}
		PROGRAM_INC_PROF_USES(program);
		PROGRAM_INC_INSTANCES(program);
	}
	ts_useobject(program);
	err = 0;

	instr_count = 0;
	mlev = ProgMLevel(program);
	gettimeofday(&fr->proftime, NULL);

	/* This is the 'natural' way to exit a function */
	while (stop) {

		/* Abort program if player/thing running it is recycled */
		if ((player < 0) || (player >= db_top) || ((Typeof(player) != TYPE_PLAYER) && (Typeof(player) != TYPE_THING)))
		{
			reload(fr, atop, stop);
			prog_clean(fr);
			interp_depth--;
			calc_profile_timing(program,fr);

			return NULL;
		}

		fr->instcnt++;
		instr_count++;

		if ((fr->multitask == PREEMPT) || (FLAGS(program) & BUILDER)) {
			if (mlev == 4) {
				if (tp_max_ml4_preempt_count)
				{
					if (instr_count >= tp_max_ml4_preempt_count)
						abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL);
				}
				else
					instr_count = 0;
			} else {
				/* else make sure that the program doesn't run too long */
				if (instr_count >= tp_max_instr_count)
					abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL);
			}
		} else {
			/* if in FOREGROUND or BACKGROUND mode, '0 sleep' every so often. */
			if ((fr->instcnt > tp_instr_slice * 4) && (instr_count >= tp_instr_slice)) {
				fr->pc = pc;
				reload(fr, atop, stop);
				PLAYER_SET_BLOCK(player, (!fr->been_background));
				add_muf_delay_event(0, fr->descr, player, NOTHING, NOTHING, program, fr,
									(fr->multitask ==
									 FOREGROUND) ? "FOREGROUND" : "BACKGROUND");
				interp_depth--;
				calc_profile_timing(program,fr);
				return NULL;
			}
		}
		if (((FLAGS(program) & ZOMBIE) || fr->brkpt.force_debugging) &&
				!fr->been_background &&
				controls(player, program)
		) {
			fr->brkpt.debugging = 1;
		} else {
			fr->brkpt.debugging = 0;
		}
		if (FLAGS(program) & DARK ||
			(fr->brkpt.debugging && fr->brkpt.showstack && !fr->brkpt.bypass)) {

			if ((pc->type != PROG_PRIMITIVE) || (pc->data.number != instno_debug_line))
			{
				char *m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program);

				notify_nolisten(player, m, 1);
			}
		}
		if (fr->brkpt.debugging) {
			short breakflag = 0;
			if (stop == 1 &&
					!fr->brkpt.bypass &&
					pc->type == PROG_PRIMITIVE &&
					pc->data.number == IN_RET
			) {
				/* Program is about to EXIT */
				notify_nolisten(player, "Program is about to EXIT.", 1);
				breakflag = 1;
			} else if (fr->brkpt.count) {
				for (i = 0; i < fr->brkpt.count; i++) {
					if ((!fr->brkpt.pc[i] || pc == fr->brkpt.pc[i]) &&
						/* pc matches */
						(fr->brkpt.line[i] == -1 ||
						 (fr->brkpt.lastline != pc->line &&
						  fr->brkpt.line[i] == pc->line)) &&
						/* line matches */
						(fr->brkpt.level[i] == -1 ||
						 stop <= fr->brkpt.level[i]) &&
						/* level matches */
						(fr->brkpt.prog[i] == NOTHING ||
						 fr->brkpt.prog[i] == program) &&
						/* program matches */
						(fr->brkpt.linecount[i] == -2 ||
						 (fr->brkpt.lastline != pc->line &&
						  fr->brkpt.linecount[i]-- <= 0)) &&
						/* line count matches */
						(fr->brkpt.pccount[i] == -2 ||
						 (fr->brkpt.lastpc != pc &&
						  fr->brkpt.pccount[i]-- <= 0))
						/* pc count matches */
					) {
						if (fr->brkpt.bypass) {
							if (fr->brkpt.pccount[i] == -1)
								fr->brkpt.pccount[i] = 0;
							if (fr->brkpt.linecount[i] == -1)
								fr->brkpt.linecount[i] = 0;
						} else {
							breakflag = 1;
							break;
						}
					}
				}
			}
			if (breakflag) {
				char *m;
				char buf[BUFFER_LEN];

				if (fr->brkpt.dosyspop) {
					program = sys[--stop].progref;
					pc = sys[stop].offset;
				}
				add_muf_read_event(fr->descr, player, program, fr);
				reload(fr, atop, stop);
				fr->pc = pc;
				fr->brkpt.isread = 0;
				fr->brkpt.breaknum = i;
				fr->brkpt.lastlisted = 0;
				fr->brkpt.bypass = 0;
				fr->brkpt.dosyspop = 0;
				PLAYER_SET_CURR_PROG(player, program);
				PLAYER_SET_BLOCK(player, 0);
				interp_depth--;
				if (!fr->brkpt.showstack) {
					m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program);
					notify_nolisten(player, m, 1);
				}
				if (pc <= PROGRAM_CODE(program) || (pc - 1)->line != pc->line) {
					list_proglines(player, program, fr, pc->line, 0);
				} else {
					m = show_line_prims(fr, program, pc, 15, 1);
					snprintf(buf, sizeof(buf), "     %s", m);
					notify_nolisten(player, buf, 1);
				}
				calc_profile_timing(program,fr);
				return NULL;
			}
			fr->brkpt.lastline = pc->line;
			fr->brkpt.lastpc = pc;
			fr->brkpt.bypass = 0;
		}
		if (mlev < 3) {
			if (fr->instcnt > (tp_max_instr_count * ((mlev == 2) ? 4 : 1)))
				abort_loop_hard("Maximum total instruction count exceeded.", NULL, NULL);
		}
		switch (pc->type) {
		case PROG_INTEGER:
		case PROG_FLOAT:
		case PROG_ADD:
		case PROG_OBJECT:
		case PROG_VAR:
		case PROG_LVAR:
		case PROG_SVAR:
		case PROG_STRING:
		case PROG_LOCK:
		case PROG_MARK:
		case PROG_ARRAY:
			if (atop >= STACK_SIZE)
				abort_loop("Stack overflow.", NULL, NULL);
			copyinst(pc, arg + atop);
			pc++;
			atop++;
			break;

		case PROG_LVAR_AT:
		case PROG_LVAR_AT_CLEAR:
			{
				struct inst *tmp;
				struct localvars *lv;

				if (atop >= STACK_SIZE)
					abort_loop("Stack overflow.", NULL, NULL);

				if (pc->data.number >= MAX_VAR || pc->data.number < 0)
					abort_loop("Scoped variable number out of range.", NULL, NULL);

				lv = localvars_get(fr, program);
				tmp = &(lv->lvars[pc->data.number]);

				copyinst(tmp, arg + atop);

				if (pc->type == PROG_LVAR_AT_CLEAR) {
					CLEAR(tmp);
					tmp->type			= PROG_INTEGER;
					tmp->data.number	= 0;
				}

				pc++;
				atop++;
			}
			break;

		case PROG_LVAR_BANG:
			{
				struct inst *the_var;
				struct localvars *lv;
				if (atop < 1)
					abort_loop("Stack Underflow.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);

				if (pc->data.number >= MAX_VAR || pc->data.number < 0)
					abort_loop("Scoped variable number out of range.", NULL, NULL);

				lv = localvars_get(fr, program);
				the_var = &(lv->lvars[pc->data.number]);

				CLEAR(the_var);
				temp1 = arg + --atop;
				*the_var = *temp1;
				pc++;
			}
			break;

		case PROG_SVAR_AT:
		case PROG_SVAR_AT_CLEAR:
			{
				struct inst *tmp;

				if (atop >= STACK_SIZE)
					abort_loop("Stack overflow.", NULL, NULL);

				tmp = scopedvar_get(fr, 0, pc->data.number);
				if (!tmp)
					abort_loop("Scoped variable number out of range.", NULL, NULL);

				copyinst(tmp, arg + atop);

				if (pc->type == PROG_SVAR_AT_CLEAR) {
					CLEAR(tmp);

					tmp->type			= PROG_INTEGER;
					tmp->data.number	= 0;
				}

				pc++;
				atop++;
			}
			break;

		case PROG_SVAR_BANG:
			{
				struct inst *the_var;
				if (atop < 1)
					abort_loop("Stack Underflow.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);

				the_var = scopedvar_get(fr, 0, pc->data.number);
				if (!the_var)
					abort_loop("Scoped variable number out of range.", NULL, NULL);

				CLEAR(the_var);
				temp1 = arg + --atop;
				*the_var = *temp1;
				pc++;
			}
			break;

		case PROG_FUNCTION:
			{
				int i = pc->data.mufproc->args;
				if (atop < i)
					abort_loop("Stack Underflow.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < i)
					abort_loop("Stack protection fault.", NULL, NULL);
				if (fr->skip_declare)
					fr->skip_declare = 0;
				else
					scopedvar_addlevel(fr, pc, pc->data.mufproc->vars);
				while (i-->0)
				{
					struct inst *tmp;
					temp1 = arg + --atop;
					tmp = scopedvar_get(fr, 0, i);
					if (!tmp)
						abort_loop_hard("Internal error: Scoped variable number out of range in FUNCTION init.", temp1, NULL);
					CLEAR(tmp);
					copyinst(temp1, tmp);
					CLEAR(temp1);
				}
				pc++;
			}
			break;

		case PROG_IF:
			if (atop < 1)
				abort_loop("Stack Underflow.", NULL, NULL);
			if (fr->trys.top && atop - fr->trys.st->depth < 1)
				abort_loop("Stack protection fault.", NULL, NULL);
			temp1 = arg + --atop;
			if (false_inst(temp1))
				pc = pc->data.call;
			else
				pc++;
			CLEAR(temp1);
			break;

		case PROG_EXEC:
			if (stop >= STACK_SIZE)
				abort_loop("System Stack Overflow", NULL, NULL);
			sys[stop].progref = program;
			sys[stop++].offset = pc + 1;
			pc = pc->data.call;
			fr->skip_declare = 0;  /* Make sure we DON'T skip var decls */
			break;

		case PROG_JMP:
			/* Don't need to worry about skipping scoped var decls here. */
			/* JMP to a function header can only happen in IN_JMP */
			pc = pc->data.call;
			break;

		case PROG_TRY:
			if (atop < 1)
				abort_loop("Stack Underflow.", NULL, NULL);
			if (fr->trys.top && atop - fr->trys.st->depth < 1)
				abort_loop("Stack protection fault.", NULL, NULL);
			temp1 = arg + --atop;
			if (temp1->type != PROG_INTEGER || temp1->data.number < 0)
				abort_loop("Argument is not a positive integer.", temp1, NULL);
			if (fr->trys.top && atop - fr->trys.st->depth < temp1->data.number)
				abort_loop("Stack protection fault.", NULL, NULL);
			if (temp1->data.number > atop)
				abort_loop("Stack Underflow.", temp1, NULL);

			fr->trys.top++;
			fr->trys.st = push_try(fr->trys.st);
			fr->trys.st->depth = atop - temp1->data.number;
			fr->trys.st->call_level = stop;
			fr->trys.st->for_count = 0;
			fr->trys.st->addr = pc->data.call;

			pc++;
			CLEAR(temp1);
			break;

		case PROG_PRIMITIVE:
			/*
			 * All pc modifiers and stuff like that should stay here,
			 * everything else call with an independent dispatcher.
			 */
			switch (pc->data.number) {
			case IN_JMP:
				if (atop < 1)
					abort_loop("Stack underflow.  Missing address.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);
				temp1 = arg + --atop;
				if (temp1->type != PROG_ADD)
					abort_loop("Argument is not an address.", temp1, NULL);
				if (temp1->data.addr->progref >= db_top ||
					temp1->data.addr->progref < 0 ||
					(Typeof(temp1->data.addr->progref) != TYPE_PROGRAM))
							abort_loop_hard("Internal error.  Invalid address.", temp1, NULL);
				if (program != temp1->data.addr->progref) {
					abort_loop("Destination outside current program.", temp1, NULL);
				}
				if (temp1->data.addr->data->type == PROG_FUNCTION) {
					fr->skip_declare = 1;
				}
				pc = temp1->data.addr->data;
				CLEAR(temp1);
				break;

			case IN_EXECUTE:
				if (atop < 1)
					abort_loop("Stack Underflow. Missing address.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);
				temp1 = arg + --atop;
				if (temp1->type != PROG_ADD)
					abort_loop("Argument is not an address.", temp1, NULL);
				if (temp1->data.addr->progref >= db_top ||
					temp1->data.addr->progref < 0 ||
					(Typeof(temp1->data.addr->progref) != TYPE_PROGRAM))
							abort_loop_hard("Internal error.  Invalid address.", temp1, NULL);
				if (stop >= STACK_SIZE)
					abort_loop("System Stack Overflow", temp1, NULL);
				sys[stop].progref = program;
				sys[stop++].offset = pc + 1;
				if (program != temp1->data.addr->progref) {
					program = temp1->data.addr->progref;
					fr->caller.st[++fr->caller.top] = program;
					mlev = ProgMLevel(program);
					PROGRAM_INC_INSTANCES(program);
				}
				pc = temp1->data.addr->data;
				CLEAR(temp1);
				break;

			case IN_CALL:
				if (atop < 1)
					abort_loop("Stack Underflow. Missing dbref argument.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);
				temp1 = arg + --atop;
				temp2 = 0;
				if (temp1->type != PROG_OBJECT) {
					temp2 = temp1;
					if (atop < 1)
						abort_loop("Stack Underflow. Missing dbref of func.", temp1, NULL);
					if (fr->trys.top && atop - fr->trys.st->depth < 1)
						abort_loop("Stack protection fault.", NULL, NULL);
					temp1 = arg + --atop;
					if (temp2->type != PROG_STRING)
						abort_loop("Public Func. name string required. (2)", temp1, temp2);
					if (!temp2->data.string)
						abort_loop("Null string not allowed. (2)", temp1, temp2);
				}
				if (temp1->type != PROG_OBJECT)
					abort_loop("Dbref required. (1)", temp1, temp2);
				if (!valid_object(temp1)
					|| Typeof(temp1->data.objref) != TYPE_PROGRAM)
					abort_loop("Invalid object.", temp1, temp2);
				if (!(PROGRAM_CODE(temp1->data.objref))) {
					struct line *tmpline;

					tmpline = PROGRAM_FIRST(temp1->data.objref);
					PROGRAM_SET_FIRST(temp1->data.objref,
									  (struct line *) read_program(temp1->data.objref));
					do_compile(-1, OWNER(temp1->data.objref), temp1->data.objref, 0);
					free_prog_text(PROGRAM_FIRST(temp1->data.objref));
					PROGRAM_SET_FIRST(temp1->data.objref, tmpline);
					if (!(PROGRAM_CODE(temp1->data.objref)))
						abort_loop("Program not compilable.", temp1, temp2);
				}
				if (ProgMLevel(temp1->data.objref) == 0)
					abort_loop("Permission denied", temp1, temp2);
				if (mlev < 4 && OWNER(temp1->data.objref) != ProgUID
					&& !Linkable(temp1->data.objref))
							abort_loop("Permission denied", temp1, temp2);
				if (stop >= STACK_SIZE)
					abort_loop("System Stack Overflow", temp1, temp2);
				sys[stop].progref = program;
				sys[stop].offset = pc + 1;
				if (!temp2) {
					pc = PROGRAM_START(temp1->data.objref);
				} else {
					struct publics *pbs;
					int tmpint;

					pbs = PROGRAM_PUBS(temp1->data.objref);
					while (pbs) {
						tmpint = string_compare(temp2->data.string->data, pbs->subname);
						if (!tmpint)
							break;
						pbs = pbs->next;
					}
					if (!pbs)
						abort_loop("PUBLIC or WIZCALL function not found. (2)", temp2, temp2);
					if (mlev < pbs->mlev)
						abort_loop("Insufficient permissions to call WIZCALL function. (2)",
								   temp2, temp2);
					pc = pbs->addr.ptr;
				}
				stop++;
				if (temp1->data.objref != program) {
					calc_profile_timing(program,fr);
					gettimeofday(&fr->proftime, NULL);
					program = temp1->data.objref;
					fr->caller.st[++fr->caller.top] = program;
					PROGRAM_INC_INSTANCES(program);
					mlev = ProgMLevel(program);
				}
				PROGRAM_INC_PROF_USES(program);
				ts_useobject(program);
				CLEAR(temp1);
				if (temp2)
					CLEAR(temp2);
				break;

			case IN_RET:
				if (stop > 1 && program != sys[stop - 1].progref) {
					if (sys[stop - 1].progref >= db_top ||
						sys[stop - 1].progref < 0 ||
						(Typeof(sys[stop - 1].progref) != TYPE_PROGRAM))
								abort_loop_hard("Internal error.  Invalid address.", NULL, NULL);
					calc_profile_timing(program,fr);
					gettimeofday(&fr->proftime, NULL);
					PROGRAM_DEC_INSTANCES(program);
					program = sys[stop - 1].progref;
					mlev = ProgMLevel(program);
					fr->caller.top--;
				}
				scopedvar_poplevel(fr);
				pc = sys[--stop].offset;
				break;

			case IN_CATCH:
			case IN_CATCH_DETAILED:
				{
					int depth;

					if (!(fr->trys.top))
						abort_loop_hard("Internal error.  TRY stack underflow.", NULL, NULL);

					depth = fr->trys.st->depth;
					while (atop > depth) {
						temp1 = arg + --atop;
						CLEAR(temp1);
					}

					while (fr->trys.st->for_count-->0) {
						CLEAR(&fr->fors.st->cur);
						CLEAR(&fr->fors.st->end);
						fr->fors.top--;
						fr->fors.st = pop_for(fr->fors.st);
					}

					fr->trys.top--;
					fr->trys.st = pop_try(fr->trys.st);

					if (pc->data.number == IN_CATCH) {
						/* IN_CATCH */
						if (fr->errorstr) {
							arg[atop].type = PROG_STRING;
							arg[atop++].data.string = alloc_prog_string(fr->errorstr);
							free(fr->errorstr);
							fr->errorstr = NULL;
						} else {
							arg[atop].type = PROG_STRING;
							arg[atop++].data.string = NULL;
						}
						if (fr->errorinst) {
							free(fr->errorinst);
							fr->errorinst = NULL;
						}
					} else {
						/* IN_CATCH_DETAILED */
						stk_array *nu = new_array_dictionary();
						if (fr->errorstr) {
							array_set_strkey_strval(&nu, "error", fr->errorstr);
							free(fr->errorstr);
							fr->errorstr = NULL;
						}
						if (fr->errorinst) {
							array_set_strkey_strval(&nu, "instr", fr->errorinst);
							free(fr->errorinst);
							fr->errorinst = NULL;
						}
						array_set_strkey_intval(&nu, "line", fr->errorline);
						array_set_strkey_refval(&nu, "program", fr->errorprog);
						arg[atop].type = PROG_ARRAY;
						arg[atop++].data.array = nu;
					}
					reload(fr, atop, stop);
				}
				pc++;
				break;

			case IN_EVENT_WAITFOR:
				if (atop < 1)
					abort_loop("Stack Underflow. Missing eventID list array argument.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);
				temp1 = arg + --atop;
				if (temp1->type != PROG_ARRAY)
					abort_loop("EventID string list array expected.", temp1, NULL);
				if (temp1->data.array && temp1->data.array->type != ARRAY_PACKED)
					abort_loop("Argument must be a list array of eventid strings.", temp1, NULL);
				if (!array_is_homogenous(temp1->data.array, PROG_STRING))
					abort_loop("Argument must be a list array of eventid strings.", temp1, NULL);
				fr->pc = pc + 1;
				reload(fr, atop, stop);

				{
					int i, outcount;
					int count = array_count(temp1->data.array);
					char** events = (char**)malloc(count * sizeof(char**));
					for (outcount = i = 0; i < count; i++) {
						char *val = array_get_intkey_strval(temp1->data.array, i);
						if (val != NULL) {
							int found = 0;
							int j;
							for (j = 0; j < outcount; j++) {
								if (!strcmp(events[j], val)) {
									found = 1;
									break;
								}
							}
							if (!found) {
								events[outcount++] = val;
							}
						}
					}
					muf_event_register_specific(player, program, fr, outcount, events);
					free(events);
				}

				PLAYER_SET_BLOCK(player, (!fr->been_background));
				CLEAR(temp1);
				interp_depth--;
				calc_profile_timing(program,fr);
				return NULL;
				/* NOTREACHED */
				break;

			case IN_READ:
				if (writeonly)
					abort_loop("Program is write-only.", NULL, NULL);
				if (fr->multitask == BACKGROUND)
					abort_loop("BACKGROUND programs are write only.", NULL, NULL);
				reload(fr, atop, stop);
				fr->brkpt.isread = 1;
				fr->pc = pc + 1;
				PLAYER_SET_CURR_PROG(player, program);
				PLAYER_SET_BLOCK(player, 0);
				add_muf_read_event(fr->descr, player, program, fr);
				interp_depth--;
				calc_profile_timing(program,fr);
				return NULL;
				/* NOTREACHED */
				break;

			case IN_SLEEP:
				if (atop < 1)
					abort_loop("Stack Underflow.", NULL, NULL);
				if (fr->trys.top && atop - fr->trys.st->depth < 1)
					abort_loop("Stack protection fault.", NULL, NULL);
				temp1 = arg + --atop;
				if (temp1->type != PROG_INTEGER)
					abort_loop("Invalid argument type.", temp1, NULL);
				fr->pc = pc + 1;
				reload(fr, atop, stop);
				if (temp1->data.number < 0)
					abort_loop("Timetravel beyond scope of muf.", temp1, NULL);
				add_muf_delay_event(temp1->data.number, fr->descr, player,
									NOTHING, NOTHING, program, fr, "SLEEPING");
				PLAYER_SET_BLOCK(player, (!fr->been_background));
				interp_depth--;
				calc_profile_timing(program,fr);
				return NULL;
				/* NOTREACHED */
				break;

			default:
				nargs = 0;
				reload(fr, atop, stop);
				tmp = atop;
				prim_func[pc->data.number - 1] (player, program, mlev, pc, arg, &tmp, fr);
				atop = tmp;
				pc++;
				break;
			}					/* switch */
			break;
		case PROG_CLEARED:
			log_status("WARNING: attempt to execute instruction cleared by %s:%hd in program %d",
					   (char*)pc->data.addr, pc->line, program);
			pc = NULL;
			abort_loop_hard("Program internal error. Program erroneously freed from memory.",
							NULL, NULL);
		default:
			pc = NULL;
			abort_loop_hard("Program internal error. Unknown instruction type.",
							NULL, NULL);
		}						/* switch */
		if (err) {
			if (err != ERROR_DIE_NOW && fr->trys.top) {
				while (fr->trys.st->call_level < stop) {
					if (stop > 1 && program != sys[stop - 1].progref) {
						if (sys[stop - 1].progref >= db_top ||
							sys[stop - 1].progref < 0 ||
							(Typeof(sys[stop - 1].progref) != TYPE_PROGRAM))
									abort_loop_hard("Internal error.  Invalid address.", NULL, NULL);
						calc_profile_timing(program,fr);
						gettimeofday(&fr->proftime, NULL);
						PROGRAM_DEC_INSTANCES(program);
						program = sys[stop - 1].progref;
						mlev = ProgMLevel(program);
						fr->caller.top--;
					}
					scopedvar_poplevel(fr);
					stop--;
				}

				pc = fr->trys.st->addr;
				err = 0;
			} else {
				reload(fr, atop, stop);
				prog_clean(fr);
				PLAYER_SET_BLOCK(player, 0);
				interp_depth--;
				calc_profile_timing(program,fr);
				return NULL;
			}
		}
	}							/* while */

	PLAYER_SET_BLOCK(player, 0);
	if (atop) {
		struct inst *rv;

		if (rettyp) {
			copyinst(arg + atop - 1, &retval);
			rv = &retval;
		} else {
			if (!false_inst(arg + atop - 1)) {
				rv = (struct inst *) 1;
			} else {
				rv = NULL;
			}
		}
		reload(fr, atop, stop);
		prog_clean(fr);
		interp_depth--;
		calc_profile_timing(program,fr);
		return rv;
	}
	reload(fr, atop, stop);
	prog_clean(fr);
	interp_depth--;
	calc_profile_timing(program,fr);
	return NULL;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #11
0
void
disassemble(dbref player, dbref program)
{
	struct inst *curr;
	struct inst *codestart;
	int i;
	char buf[BUFFER_LEN];

	codestart = curr = PROGRAM_CODE(program);
	if (!PROGRAM_SIZ(program)) {
		notify(player, "Nothing to disassemble!");
		return;
	}
	for (i = 0; i < PROGRAM_SIZ(program); i++, curr++) {
		switch (curr->type) {
		case PROG_PRIMITIVE:
			if (curr->data.number >= BASE_MIN && curr->data.number <= BASE_MAX)
				snprintf(buf, sizeof(buf), "%d: (line %d) PRIMITIVE: %s", i,
						curr->line, base_inst[curr->data.number - BASE_MIN]);
			else
				snprintf(buf, sizeof(buf), "%d: (line %d) PRIMITIVE: %d", i, curr->line, curr->data.number);
			break;
		case PROG_MARK:
			snprintf(buf, sizeof(buf), "%d: (line %d) MARK", i, curr->line);
			break;
		case PROG_STRING:
			snprintf(buf, sizeof(buf), "%d: (line %d) STRING: \"%s\"", i, curr->line,
					curr->data.string ? curr->data.string->data : "");
			break;
		case PROG_ARRAY:
			snprintf(buf, sizeof(buf), "%d: (line %d) ARRAY: %d items", i, curr->line,
					curr->data.array ? curr->data.array->items : 0);
			break;
		case PROG_FUNCTION:
			snprintf(buf, sizeof(buf), "%d: (line %d) FUNCTION: %s, VARS: %d, ARGS: %d", i, curr->line,
					curr->data.mufproc->procname ? curr->data.mufproc->procname : "",
					curr->data.mufproc->vars, curr->data.mufproc->args);
			break;
		case PROG_LOCK:
			snprintf(buf, sizeof(buf), "%d: (line %d) LOCK: [%s]", i, curr->line,
					curr->data.lock == TRUE_BOOLEXP ? "TRUE_BOOLEXP" :
					unparse_boolexp(0, curr->data.lock, 0));
			break;
		case PROG_INTEGER:
			snprintf(buf, sizeof(buf), "%d: (line %d) INTEGER: %d", i, curr->line, curr->data.number);
			break;
		case PROG_FLOAT:
			snprintf(buf, sizeof(buf), "%d: (line %d) FLOAT: %.17g", i, curr->line, curr->data.fnumber);
			break;
		case PROG_ADD:
			snprintf(buf, sizeof(buf), "%d: (line %d) ADDRESS: %d", i,
					curr->line, (int)(curr->data.addr->data - codestart));
			break;
		case PROG_TRY:
			snprintf(buf, sizeof(buf), "%d: (line %d) TRY: %d", i, curr->line, (int)(curr->data.call - codestart));
			break;
		case PROG_IF:
			snprintf(buf, sizeof(buf), "%d: (line %d) IF: %d", i, curr->line, (int)(curr->data.call - codestart));
			break;
		case PROG_JMP:
			snprintf(buf, sizeof(buf), "%d: (line %d) JMP: %d", i, curr->line, (int)(curr->data.call - codestart));
			break;
		case PROG_EXEC:
			snprintf(buf, sizeof(buf), "%d: (line %d) EXEC: %d", i, curr->line, (int)(curr->data.call - codestart));
			break;
		case PROG_OBJECT:
			snprintf(buf, sizeof(buf), "%d: (line %d) OBJECT REF: %d", i, curr->line, curr->data.number);
			break;
		case PROG_VAR:
			snprintf(buf, sizeof(buf), "%d: (line %d) VARIABLE: %d", i, curr->line, curr->data.number);
			break;
		case PROG_SVAR:
			snprintf(buf, sizeof(buf), "%d: (line %d) SCOPEDVAR: %d (%s)", i, curr->line, curr->data.number, scopedvar_getname_byinst(curr, curr->data.number));
			break;
		case PROG_SVAR_AT:
			snprintf(buf, sizeof(buf), "%d: (line %d) FETCH SCOPEDVAR: %d (%s)", i, curr->line, curr->data.number, scopedvar_getname_byinst(curr, curr->data.number));
			break;
		case PROG_SVAR_AT_CLEAR:
			snprintf(buf, sizeof(buf), "%d: (line %d) FETCH SCOPEDVAR (clear optim): %d (%s)", i, curr->line, curr->data.number, scopedvar_getname_byinst(curr, curr->data.number));
			break;
		case PROG_SVAR_BANG:
			snprintf(buf, sizeof(buf), "%d: (line %d) SET SCOPEDVAR: %d (%s)", i, curr->line, curr->data.number, scopedvar_getname_byinst(curr, curr->data.number));
			break;
		case PROG_LVAR:
			snprintf(buf, sizeof(buf), "%d: (line %d) LOCALVAR: %d", i, curr->line, curr->data.number);
			break;
		case PROG_LVAR_AT:
			snprintf(buf, sizeof(buf), "%d: (line %d) FETCH LOCALVAR: %d", i, curr->line, curr->data.number);
			break;
		case PROG_LVAR_AT_CLEAR:
			snprintf(buf, sizeof(buf), "%d: (line %d) FETCH LOCALVAR (clear optim): %d", i, curr->line, curr->data.number);
			break;
		case PROG_LVAR_BANG:
			snprintf(buf, sizeof(buf), "%d: (line %d) SET LOCALVAR: %d", i, curr->line, curr->data.number);
			break;
		case PROG_CLEARED:
			snprintf(buf, sizeof(buf), "%d: (line ?) CLEARED INST AT %s:%d", i, (char *) curr->data.addr,
					curr->line);
		default:
			snprintf(buf, sizeof(buf), "%d: (line ?) UNKNOWN INST", i);
		}
		notify(player, buf);
	}
}