Example #1
0
void prepareVM(VMContext ctx, ScriptCInstruction inst, long code_length) {
  const void **table = (const void **)vm_execute(ctx, NULL);
  for(long i = 0; i < code_length; i++) {
    inst->addr = (const void*)table[inst->op];
    ++inst;
  }
}
Example #2
0
void ddbg_continue_vm()
{
    vm->halted = false;
    vm->sleep_cycles = 0;
    dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("continue")), 0);
    vm_execute(vm, NULL);
    printd(LEVEL_DEFAULT, "\n");
}
Example #3
0
void ddbg_step_over()
{
    uint16_t inst, op_a, op_b, offset = 1, bp;
    inst = INSTRUCTION_GET_OP(vm->ram[vm->pc]);
    op_a = INSTRUCTION_GET_A(vm->ram[vm->pc]);
    op_b = INSTRUCTION_GET_B(vm->ram[vm->pc]);
    vm->sleep_cycles = 0;

    if (op_a == NXT)
        offset += 1;
    if (op_a == NXT_LIT)
        offset += 1;

    if (op_b == NXT)
        offset += 1;
    if (op_b == NXT_LIT)
        offset += 1;

    if (inst == NBOP_RESERVED)
    {
        if (op_b == NBOP_JSR)
        {
            bp = op_a;
        }
    }
    else
    {
        bp = vm->pc + offset;
    }

    list_append(&breakpoints, breakpoint_create(bp, true, true));
    vm->halted = false;
    vm_execute(vm, NULL);

    // Handle custom Lua commands.
    dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("next")), 0);
}
Example #4
0
int main(int argc, char* argv[])
{
    // Define our variables.
    FILE* load;
    uint16_t flash[0x10000];
    char leading[0x100];
    unsigned int i;
    bool uread = true;
    vm_t* vm;
    int nerrors;
    bstring ss, st;
    host_context_t* dtemu = malloc(sizeof(host_context_t));
    const char* warnprefix = "no-";

    // Define arguments.
    struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
    struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file, or - to read from standard input.");
    struct arg_file* execution_dump_file = arg_file0("e", "execution-dump", "<file>", "Produce a very large execution dump file.");
    struct arg_lit* debug_mode = arg_lit0("d", "debug", "Show each executed instruction.");
    struct arg_lit* terminate_mode = arg_lit0("t", "show-on-terminate", "Show state of machine when program is terminated.");
    struct arg_lit* headless_mode = arg_lit0("h", "headless", "Run machine witout displaying monitor and SPED output");
    struct arg_lit* legacy_mode = arg_lit0("l", "legacy", "Automatically initialize hardware to legacy values.");
    struct arg_str* warning_policies = arg_strn("W", NULL, "policy", 0, _WARN_COUNT * 2 + 10, "Modify warning policies.");
    struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions).");
    struct arg_lit* verbose = arg_litn("v", NULL, 0, LEVEL_EVERYTHING - LEVEL_DEFAULT, "Increase verbosity.");
    struct arg_lit* quiet = arg_litn("q", NULL,  0, LEVEL_DEFAULT - LEVEL_SILENT, "Decrease verbosity.");
    struct arg_int* radiation = arg_intn("r", NULL, "<n>", 0, 1, "Radiation factor (higher is less radiation)");
    struct arg_lit* catch_fire = arg_lit0("c", "catch-fire", "The virtual machine should catch fire instead of halting.");
    struct arg_end* end = arg_end(20);
    void* argtable[] = { input_file, warning_policies, debug_mode, execution_dump_file, terminate_mode, headless_mode, legacy_mode, little_endian_mode, radiation, catch_fire, verbose, quiet, end };

    // Parse arguments.
    nerrors = arg_parse(argc, argv, argtable);

    if (nerrors != 0 || show_help->count != 0)
    {
        if (show_help->count != 0)
            arg_print_errors(stdout, end, "emulator");

        printd(LEVEL_DEFAULT, "syntax:\n    dtemu");
        arg_print_syntax(stderr, argtable, "\n");
        printd(LEVEL_DEFAULT, "options:\n");
        arg_print_glossary(stderr, argtable, "      %-25s %s\n");
        arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
        return 1;
    }

    // Set verbosity level.
    debug_setlevel(LEVEL_DEFAULT + verbose->count - quiet->count);
    
    // Show version information.
    version_print(bautofree(bfromcstr("Emulator")));

    // Set global path variable.
    osutil_setarg0(bautofree(bfromcstr(argv[0])));

    // Set endianness.
    isetmode(little_endian_mode->count == 0 ? IMODE_BIG : IMODE_LITTLE);

    // Set up warning policies.
    dsetwarnpolicy(warning_policies);
    
    // Set up error handling.
    if (dsethalt())
    {
        // Handle the error.
        dautohandle();
        printd(LEVEL_ERROR, "emulator: error occurred.\n");

        arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
        return 1;
    }

    // Zero out the flash space.
    for (i = 0; i < 0x10000; i++)
        flash[i] = 0x0;

    // Zero out the leading space.
    for (i = 0; i < 0x100; i++)
        leading[i] = 0x0;

    // Load from either file or stdin.
    if (strcmp(input_file->filename[0], "-") != 0)
    {
        // Open file.
        load = fopen(input_file->filename[0], "rb");

        if (load == NULL)
            dhalt(ERR_EMU_LOAD_FILE_FAILED, input_file->filename[0]);
    }
    else
    {
        // Windows needs stdin in binary mode.
#ifdef _WIN32
        _setmode(_fileno(stdin), _O_BINARY);
#endif

        // Set load to stdin.
        load = stdin;
    }
    
    // Read leading component.
    for (i = 0; i < strlen(ldata_objfmt); i++)
        leading[i] = fgetc(load);
    fseek(load, 0, SEEK_SET);

    // Read up to 0x10000 words.
    for (i = 0; i < 0x10000 && !feof(load); i++)
        iread(&flash[i], load);
    fclose(load);

    // Check to see if the first X bytes matches the header
    // for intermediate code and stop if it does.
    ss = bfromcstr("");
    st = bfromcstr(ldata_objfmt);
    for (i = 0; i < strlen(ldata_objfmt); i++)
        bconchar(ss, leading[i]);
    if (biseq(ss, st))
        dhalt(ERR_INTERMEDIATE_EXECUTION, NULL);

    // Set up the host context.
    glfwInit();
    dtemu->create_context = &dtemu_create_context;
    dtemu->activate_context = &dtemu_activate_context;
    dtemu->swap_buffers = &dtemu_swap_buffers;
    dtemu->destroy_context = &dtemu_destroy_context;
    dtemu->get_ud = &dtemu_get_ud;

    // And then use the VM.
    vm = vm_create();
    vm->debug = (debug_mode->count > 0);
    vm_flash(vm, flash);

    // Set radiation and catch fire settings.
    if (radiation->count == 1)
        vm->radiation_factor = radiation->ival[0];
    if (catch_fire->count == 1)
        vm->can_fire = true;

    // Init hardware.
    vm_hw_clock_init(vm);

    if (headless_mode->count < 1)
        vm->host = dtemu;

    vm_hw_sped3_init(vm);
    vm_hw_lem1802_init(vm);
    vm_hw_m35fd_init(vm);
    vm_hw_lua_init(vm);

    if (legacy_mode->count > 0)
    {
        for (i = 0; i < vm_hw_count(vm); i++) {

            hw_t* device = vm_hw_get_device(vm, i);
            if (device == NULL)
                continue;

            if (device->id == 0x7349F615 && device->manufacturer == 0x1C6C8B36)
            {
                vm_hw_lem1802_mem_set_screen((struct lem1802_hardware*)device->userdata, 0x8000);
                break;
            }
        }
    }

    vm_execute(vm, execution_dump_file->count > 0 ? execution_dump_file->filename[0] : NULL);

    if (terminate_mode->count > 0)
    {
        fprintf(stderr, "\n");
        fprintf(stderr, "A:   0x%04X     [A]:    0x%04X\n", vm->registers[REG_A], vm->ram[vm->registers[REG_A]]);
        fprintf(stderr, "B:   0x%04X     [B]:    0x%04X\n", vm->registers[REG_B], vm->ram[vm->registers[REG_B]]);
        fprintf(stderr, "C:   0x%04X     [C]:    0x%04X\n", vm->registers[REG_C], vm->ram[vm->registers[REG_C]]);
        fprintf(stderr, "X:   0x%04X     [X]:    0x%04X\n", vm->registers[REG_X], vm->ram[vm->registers[REG_X]]);
        fprintf(stderr, "Y:   0x%04X     [Y]:    0x%04X\n", vm->registers[REG_Y], vm->ram[vm->registers[REG_Y]]);
        fprintf(stderr, "Z:   0x%04X     [Z]:    0x%04X\n", vm->registers[REG_Z], vm->ram[vm->registers[REG_Z]]);
        fprintf(stderr, "I:   0x%04X     [I]:    0x%04X\n", vm->registers[REG_I], vm->ram[vm->registers[REG_I]]);
        fprintf(stderr, "J:   0x%04X     [J]:    0x%04X\n", vm->registers[REG_J], vm->ram[vm->registers[REG_J]]);
        fprintf(stderr, "PC:  0x%04X     SP:    0x%04X\n", vm->pc, vm->sp);
        fprintf(stderr, "EX:  0x%04X     IA:    0x%04X\n", vm->ex, vm->ia);
    }

    vm_hw_lua_free(vm);
    vm_free(vm);

    arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
    glfwTerminate();
    return 0;
}
Example #5
0
int main(int argc, char* argv[])
{
	// Define our variables.
	FILE* load;
	uint16_t flash[0x10000];
	char leading[0x100];
	unsigned int i;
	bool uread = true;
	vm_t* vm;
	int nerrors;
	bstring ss, st;

	// Define arguments.
	struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
	struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file, or - to read from standard input.");
	struct arg_file* execution_dump_file = arg_file0("e", "execution-dump", "<file>", "Produce a very large execution dump file.");
	struct arg_lit* debug_mode = arg_lit0("d", "debug", "Show each executed instruction.");
	struct arg_lit* terminate_mode = arg_lit0("t", "show-on-terminate", "Show state of machine when program is terminated.");
	struct arg_lit* legacy_mode = arg_lit0("l", "legacy", "Automatically initialize hardware to legacy values.");
	struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions).");
	struct arg_lit* verbose = arg_litn("v", NULL, 0, LEVEL_EVERYTHING - LEVEL_DEFAULT, "Increase verbosity.");
	struct arg_lit* quiet = arg_litn("q", NULL,  0, LEVEL_DEFAULT - LEVEL_SILENT, "Decrease verbosity.");
	struct arg_end* end = arg_end(20);
	void* argtable[] = { input_file, debug_mode, execution_dump_file, terminate_mode, legacy_mode, little_endian_mode, verbose, quiet, end };

	// Parse arguments.
	nerrors = arg_parse(argc, argv, argtable);

	version_print(bautofree(bfromcstr("Emulator")));
	if (nerrors != 0 || show_help->count != 0)
	{
		if (show_help->count != 0)
			arg_print_errors(stdout, end, "emulator");

		printd(LEVEL_DEFAULT, "syntax:\n    dtemu");
		arg_print_syntax(stderr, argtable, "\n");
		printd(LEVEL_DEFAULT, "options:\n");
		arg_print_glossary(stderr, argtable, "	  %-25s %s\n");
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// Set verbosity level.
	debug_setlevel(LEVEL_DEFAULT + verbose->count - quiet->count);

	// Set global path variable.
	osutil_setarg0(bautofree(bfromcstr(argv[0])));

	// Set endianness.
	isetmode(little_endian_mode->count == 0 ? IMODE_BIG : IMODE_LITTLE);

	// Zero out the flash space.
	for (i = 0; i < 0x10000; i++)
		flash[i] = 0x0;

	// Zero out the leading space.
	for (i = 0; i < 0x100; i++)
		leading[i] = 0x0;

	// Load from either file or stdin.
	if (strcmp(input_file->filename[0], "-") != 0)
	{
		// Open file.
		load = fopen(input_file->filename[0], "rb");

		if (load == NULL)
		{
			fprintf(stderr, "emulator: unable to load %s from disk.\n", argv[1]);
			arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
			return 1;
		}
	}
	else
	{
		// Windows needs stdin in binary mode.
#ifdef _WIN32
		_setmode(_fileno(stdin), _O_BINARY);
#endif

		// Set load to stdin.
		load = stdin;
	}

	// Read up to 0x10000 words.
	for (i = 0; i < 0x10000 && !feof(load); i++)
		iread(&flash[i], load);
	fclose(load);

	// Check to see if the first X bytes matches the header
	// for intermediate code and stop if it does.
	ss = bfromcstr("");
	st = bfromcstr(ldata_objfmt);
	for (i = 0; i < strlen(ldata_objfmt); i++)
		bconchar(ss, leading[i]);
	if (biseq(ss, st))
	{
		fprintf(stderr, "emulator: it appears you passed intermediate code for execution.  link\n");
		fprintf(stderr, "	   the input code with the toolchain linker to execute it.\n");
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// And then use the VM.
	vm = vm_create();
	vm->debug = (debug_mode->count > 0);
	vm_flash(vm, flash);
	vm_hw_timer_init(vm);
	vm_hw_io_init(vm);
	vm_hw_lem1802_init(vm);
	vm_hw_lua_init(vm);
	if (legacy_mode->count > 0)
	{
		vm_hw_lem1802_mem_set_screen(vm, 0x8000);
		vm_hw_io_set_legacy(true);
	}
	vm_execute(vm, execution_dump_file->count > 0 ? execution_dump_file->filename[0] : NULL);

#ifdef __EMSCRIPTEN__
	printd(LEVEL_WARNING, "warning: not cleaning up resources in Emscripten.\n");
#else
	if (terminate_mode->count > 0)
	{
		fprintf(stderr, "\n");
		fprintf(stderr, "A:   0x%04X	 [A]:	0x%04X\n", vm->registers[REG_A], vm->ram[vm->registers[REG_A]]);
		fprintf(stderr, "B:   0x%04X	 [B]:	0x%04X\n", vm->registers[REG_B], vm->ram[vm->registers[REG_B]]);
		fprintf(stderr, "C:   0x%04X	 [C]:	0x%04X\n", vm->registers[REG_C], vm->ram[vm->registers[REG_C]]);
		fprintf(stderr, "X:   0x%04X	 [X]:	0x%04X\n", vm->registers[REG_X], vm->ram[vm->registers[REG_X]]);
		fprintf(stderr, "Y:   0x%04X	 [Y]:	0x%04X\n", vm->registers[REG_Y], vm->ram[vm->registers[REG_Y]]);
		fprintf(stderr, "Z:   0x%04X	 [Z]:	0x%04X\n", vm->registers[REG_Z], vm->ram[vm->registers[REG_Z]]);
		fprintf(stderr, "I:   0x%04X	 [I]:	0x%04X\n", vm->registers[REG_I], vm->ram[vm->registers[REG_I]]);
		fprintf(stderr, "J:   0x%04X	 [J]:	0x%04X\n", vm->registers[REG_J], vm->ram[vm->registers[REG_J]]);
		fprintf(stderr, "PC:  0x%04X	 SP:	0x%04X\n", vm->pc, vm->sp);
		fprintf(stderr, "EX:  0x%04X	 IA:	0x%04X\n", vm->ex, vm->ia);
	}

	vm_hw_lua_free(vm);
	vm_hw_timer_free(vm);
	vm_hw_io_free(vm);
	vm_hw_lem1802_free(vm);
	vm_free(vm);

	arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
	return 0;
#endif
}
Example #6
0
int main(int ac, char** av)
{
	t_vm*		vm		= vm_initialize();
	t_process*	process = (t_process*) malloc(sizeof(t_process));
	int32		i;
	t_display*		display;
	int32			update_display = 0;
	int32			was_pressed = 0;
	t_ring_buffer*	ring_buffer;

	ring_buffer = ring_buffer_initialize(10, free);

	if (load_cores(vm, ac, av) <= 0)
		return -1;

	display = display_initialize(800, 600);
	vm_set_print_callback(vm, main_debug_print, ring_buffer);

	if (1)
	{
		while (vm->process_count && !display_should_exit(display))
		{
			vm->cycle_current++;
			update_display = 1;
			int process_count = vm->process_count;
			for (i = 0; i < process_count; ++i)
			{
				t_process* process = vm->processes[i];
				if (process->cycle_wait <= 0)
				{
					update_display = 0;

					vm_reset_process_io_op(process);
					if (process->current_opcode)
						vm_execute(vm, process);
					vm_get_opcode(vm, process);
				}
				else
					process->cycle_wait--;
			}

			if (vm->cycle_current > vm->cycle_to_die)
			{
				vm->cycle_current = 0;
				vm_kill_process_if_no_live(vm);
			}

			vm_clean_dead_process(vm);
//			update_display = 0;
			if (display_update_input(display) || update_display == 0)
			{
				display_print_ring_buffer(display, 0, 0, ring_buffer);
				display_step(vm, display);
			}

		}
	}
	else
	{
		int32 execute_one = 0;

		int32 current_keys_state[GLFW_KEY_LAST];
		int32 previous_keys_state[GLFW_KEY_LAST];

		memset(previous_keys_state, 0, GLFW_KEY_LAST * sizeof(int32));
		memset(current_keys_state, 0, GLFW_KEY_LAST * sizeof(int32));
		display_step(vm, display);
		while (vm->process_count && !display_should_exit(display))
		{
			int32 executed = 0;
			int32 print_processes;
			int32 process_count = 0;

			current_keys_state[GLFW_KEY_S] = display_key_pressed(display, GLFW_KEY_S);
			current_keys_state[GLFW_KEY_P] = display_key_pressed(display, GLFW_KEY_P);

			if (!execute_one)
				execute_one = previous_keys_state[GLFW_KEY_S] && !current_keys_state[GLFW_KEY_S];
			print_processes = previous_keys_state[GLFW_KEY_P] && !current_keys_state[GLFW_KEY_P];
			memcpy(previous_keys_state, current_keys_state, sizeof(int32) * GLFW_KEY_LAST);

			if (execute_one)
				vm->cycle_current++;
			for (i = 0; i < vm->process_count; ++i)
			{
				t_process* process = vm->processes[i];
				if (print_processes)
					vm_debug_print_process(vm, process);
				if (execute_one)
				{
					if (process->cycle_wait <= 0)
					{
						vm_reset_process_io_op(process);
						vm_execute(vm, process);
						vm_get_opcode(vm, process);
						executed++;
						if (vm->live_count >= NBR_LIVE)
						{
							vm->live_count = 0;
							vm->cycle_to_die -= vm->cycle_delta;
						}
					}
					process->cycle_wait--;
				}
			}
			if (executed)
				execute_one = 0;
			if (vm->cycle_current > vm->cycle_to_die)
			{
				vm->cycle_current = 0;
				vm_kill_process_if_no_live(vm);
			}
			vm_clean_dead_process(vm);
			executed += display_update_input(display);
			if (executed)
				display_step(vm, display);
			else
				glfwPollEvents();
		}
	}


	ring_buffer_destroy(ring_buffer);
	display_destroy(display);
	vm_destroy(vm);
}
Example #7
0
int main(int ac, char** av) {
	vm_t*					vm;
	display_gl_t*	display = NULL;
	int						bound;
	int						i;
	debugger_t*		debugger = NULL;

	vm = vm_initialize();

	if ( (parse_arguments(vm, ac, av) <= 0) || (check_core_endianess(vm) < 0)) {
		return -1;
	}

	bound = VM_MEMORY_SIZE / (vm->core_count - 1);
	for (i = 0; i < vm->core_count; ++i) {
		vm->cores[i]->bound.start = vm->cores[i]->start_address;
		vm->cores[i]->bound.size = bound;
	}

	memory_access_initialize(is_cpu_big_endian() != vm->big_endian);

#if defined(_DEBUG)
		vm->full_screen = 0;
#endif

#ifdef RENDER_GL
	display = display_gl_initialize(1980, 1080, vm->full_screen);
	if (vm->step != -1) {
		debugger = debugger_init(vm->dbg_same_window ? display_gl_get_window(display) : NULL);
	}
#endif

	while (vm->process_count && !display_gl_should_exit(display)) {
		int32 i;
		int update_display = 0;


		if (vm->cycle_barrier == vm->cycle_total) {
			for (i = 0; i < vm->core_count; ++i) {
				vm->cores[i]->bound.start = 0;
				vm->cores[i]->bound.size = vm->memory_size;
			}
		}

		if (vm->step != 0) {
			vm->cycle_current++;
			vm->cycle_total++;

			int32 process_count = vm->process_count;
			for (i = process_count; i > 0; --i) {
				process_t* process = vm->processes[i - 1];
				process->cycle_wait--;
				if (process->cycle_wait <= 0) {
					vm_reset_process_io_op(process);
					vm_execute(vm, process);
					update_display = 1;
					if (vm->step > 0 && (vm->step_process == NULL || vm->step_process == process) ) {
						vm->step --;
					}
				}
			}

			if (vm->cycle_current > vm->cycle_to_die) {
				vm->cycle_current = 0;
				vm_kill_process_if_no_live(vm);
				vm_clean_dead_process(vm);
			}
		} else {
			update_display = 1;
		}

	#ifdef RENDER_GL
		update_display |= display_gl_update_input(display);
		if (update_display)
		{
			float y = 1;
			y = display_gl_text(display, 0, y, 0xffffffff, "cycle to die   %d", vm->cycle_to_die);
			y = display_gl_text(display, 0, y, 0xffffffff, "live count     %d ", vm->live_count);
			y = display_gl_text(display, 0, y, 0xffffffff, "process count  %d ", vm->process_count);
			y = display_gl_text(display, 0, y, 0xffffffff, "cycle          %d ", vm->cycle_total);
			y = display_gl_text(display, 0, y, 0xffffffff, "barrier        %d ", vm->cycle_barrier);
			for (i = 0; i < vm->core_count; ++i) {
				core_t* core = vm->cores[i];
				char* name = core->header ? core->header->name : "Unknow";
				y = display_gl_text(display, 0, y, 0xffffffff, "%s %d", name, core->live_count);
			}
			display_gl_step(vm, display);
			display_gl_swap(display);
		}

		if (debugger && vm->step != 1) {
			debugger_render(debugger, vm);
		}
	#endif
	}

	print_winning_core(vm);
	if (debugger) {
		debugger_destroy(debugger);
	}
#ifdef RENDER_GL
	display_gl_destroy(display);
#endif
	vm_destroy(vm);
}
Example #8
0
void dbg_lua_handle_command(struct dbg_state* state, void* ud, freed_bstring name, list_t* parameters)
{
    struct lua_debugst* ds;
    struct customarg_entry* carg;
    char* cstr;
    unsigned int i, k;
    int paramtbl;

    // Convert the name to lowercase.
    btolower(name.ref);
    cstr = bstr2cstr(name.ref, '0');

    // Loop through all of the modules.
    for (k = 0; k < list_size(&modules); k++)
    {
        ds = list_get_at(&modules, k);

        // Set stack top (I don't know why the top of the
        // stack is negative!)
        lua_settop(ds->state, 0);

        // Search handler table for entries.
        lua_getglobal(ds->state, HANDLER_TABLE_COMMANDS_NAME);
        lua_getfield(ds->state, -1, cstr);
        if (!lua_istable(ds->state, -1))
        {
            // No such entry.
            lua_pop(ds->state, 2);
            continue;
        }

        // Call the handler function.
        lua_getfield(ds->state, -1, HANDLER_FIELD_FUNCTION_NAME);
        dbg_lua_push_state(ds, state, ud);
        lua_newtable(ds->state);
        paramtbl = lua_gettop(ds->state);
        for (i = 0; i < list_size(parameters); i++)
        {
            carg = list_get_at(parameters, i);

            lua_newtable(ds->state);
            if (carg->type == DBG_CUSTOMARG_TYPE_PATH)
                lua_pushstring(ds->state, "PATH");
            else if (carg->type == DBG_CUSTOMARG_TYPE_PARAM)
                lua_pushstring(ds->state, "PARAM");
            else if (carg->type == DBG_CUSTOMARG_TYPE_STRING)
                lua_pushstring(ds->state, "STRING");
            else
                lua_pushstring(ds->state, "NUMBER");
            lua_setfield(ds->state, -2, "type");
            if (carg->type == DBG_CUSTOMARG_TYPE_PATH)
                lua_pushstring(ds->state, carg->path->data);
            else if (carg->type == DBG_CUSTOMARG_TYPE_PARAM)
                lua_pushstring(ds->state, carg->param->data);
            else if (carg->type == DBG_CUSTOMARG_TYPE_STRING)
                lua_pushstring(ds->state, carg->string->data);
            else
                lua_pushnumber(ds->state, carg->number);
            lua_setfield(ds->state, -2, "value");
            lua_rawseti(ds->state, paramtbl, i + 1);
        }
        if (lua_pcall(ds->state, 2, 0, 0) != 0)
        {
            printd(LEVEL_ERROR, "error: unable to call debugger command handler for '%s'.\n", name.ref->data);
            printd(LEVEL_ERROR, "%s\n", lua_tostring(ds->state, -1));
            bautodestroy(name);
            bcstrfree(cstr);
            lua_pop(ds->state, 2);
            list_iterator_stop(&modules);
            list_destroy(parameters);
            return;
        }

        bautodestroy(name);
        bcstrfree(cstr);
        lua_pop(ds->state, 2);
        list_iterator_stop(&modules);
        list_destroy(parameters);

        // The command may have started the virtual machine, check the
        // status of the VM and execute if needed.
        if (state->get_vm()->halted == false)
            vm_execute(state->get_vm(), NULL);

        return;
    }

    // There is no command to handle this.
    printd(LEVEL_ERROR, "no such command found.\n");

    // Clean up.
    list_destroy(parameters);
    bautodestroy(name);
    bcstrfree(cstr);
}