Exemple #1
0
int main(int argc, char* argv[])
{
    // Define our variables.
    int nerrors, i;
    int32_t saved = 0; // The number of words saved during compression and optimization.
    struct errinfo* errval;
    const char* prepend = "error: ";
    const char* warnprefix = "no-";
    int msglen;
    char* msg;
    int target;

    // Define arguments.
    struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
    struct arg_str* target_arg = arg_str0("l", "link-as", "target", "Link as the specified object, can be 'image', 'static' or 'kernel'.");
    struct arg_file* symbol_file = arg_file0("s", "symbols", "<file>", "Produce a combined symbol file (~triples memory usage!).");
    struct arg_str* symbol_ext = arg_str0(NULL, "symbol-extension", "ext", "When -s is used, specifies the extension for symbol files.  Defaults to \"dsym16\".");
    struct arg_file* input_files = arg_filen(NULL, NULL, "<file>", 1, 100, "The input object files.");
    struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output).");
    struct arg_file* kernel_file = arg_file0("k", "kernel", "<file>", "Directly link in the specified kernel.");
    struct arg_file* jumplist_file = arg_file0("j", "jumplist", "<file>", "Link against the specified jumplist.");
    struct arg_str* warning_policies = arg_strn("W", NULL, "policy", 0, _WARN_COUNT * 2 + 10, "Modify warning policies.");
    struct arg_lit* keep_output_arg = arg_lit0(NULL, "keep-outputs", "Keep the .OUTPUT entries in the final static library (used for stdlib).");
    struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions).");
    struct arg_lit* no_short_literals_arg = arg_lit0(NULL, "no-short-literals", "Do not compress literals to short literals.");
    struct arg_int* opt_level = arg_int0("O", NULL, "<level>", "The optimization level.");
    struct arg_lit* opt_mode = arg_lit0("S", NULL, "Favour runtime speed over size when optimizing.");
    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[] = { show_help, target_arg, keep_output_arg, little_endian_mode, opt_level, opt_mode, no_short_literals_arg,
                         symbol_ext, symbol_file, kernel_file, jumplist_file, warning_policies, output_file, input_files, verbose, quiet, end
                       };

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

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

        printd(LEVEL_DEFAULT, "syntax:\n    dtld");
        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);

    // Set up warning policies.
    dsetwarnpolicy(warning_policies);

    // Set up error handling.
    if (dsethalt())
    {
        errval = derrinfo();

        // FIXME: Use bstrings here.
        msglen = strlen(derrstr[errval->errid]) + strlen(prepend) + 1;
        msg = malloc(msglen);
        memset(msg, '\0', msglen);
        strcat(msg, prepend);
        strcat(msg, derrstr[errval->errid]);
        printd(LEVEL_ERROR, msg, errval->errdata);

        // Handle the error.
        printd(LEVEL_ERROR, "linker: error occurred.\n");

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

    // Check to make sure target is correct.
    if (target_arg->count == 0)
        target = IMAGE_APPLICATION;
    else
    {
        if (strcmp(target_arg->sval[0], "image") == 0)
            target = IMAGE_APPLICATION;
        else if (strcmp(target_arg->sval[0], "static") == 0)
            target = IMAGE_STATIC_LIBRARY;
        else if (strcmp(target_arg->sval[0], "kernel") == 0)
            target = IMAGE_KERNEL;
        else
        {
            // Invalid option.
            dhalt(ERR_INVALID_TARGET_NAME, NULL);
        }
    }

    // Load all passed objects and use linker bin system to
    // produce result.
    bins_init();
    for (i = 0; i < input_files->count; i++)
        if (!bins_load(bautofree(bfromcstr(input_files->filename[i])), symbol_file->count > 0, (symbol_file->count > 0 && symbol_ext->count > 0) ? symbol_ext->sval[0] : "dsym16"))
            // Failed to load one of the input files.
            dhalt(ERR_BIN_LOAD_FAILED, input_files->filename[i]);
    bins_associate();
    bins_sectionize();
    bins_flatten(bautofree(bfromcstr("output")));
    if (target == IMAGE_KERNEL)
        bins_write_jump();
    saved = bins_optimize(
                opt_mode->count == 0 ? OPTIMIZE_SIZE : OPTIMIZE_SPEED,
                opt_level->count == 0 ? OPTIMIZE_NONE : opt_level->ival[0]);
    if (no_short_literals_arg->count == 0 && target != IMAGE_STATIC_LIBRARY)
        saved += bins_compress();
    else if (no_short_literals_arg->count == 0)
        dwarn(WARN_SKIPPING_SHORT_LITERALS_TYPE, NULL);
    else
        dwarn(WARN_SKIPPING_SHORT_LITERALS_REQUEST, NULL);
    bins_resolve(
        target == IMAGE_STATIC_LIBRARY,
        target == IMAGE_STATIC_LIBRARY);
    bins_save(
        bautofree(bfromcstr("output")),
        bautofree(bfromcstr(output_file->filename[0])),
        target,
        keep_output_arg->count > 0,
        symbol_file->count > 0 ? symbol_file->filename[0] : NULL,
        jumplist_file->count > 0 ? jumplist_file->filename[0] : NULL);
    bins_free();
    if (saved > 0)
        printd(LEVEL_DEFAULT, "linker: saved %i words during optimization.\n", saved);
    else if (saved < 0)
        printd(LEVEL_DEFAULT, "linker: increased by %i words during optimization.\n", -saved);

    arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
    return 0;
}
Exemple #2
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
}
Exemple #3
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;
}
Exemple #4
0
int main(int argc, char** argv)
{
	char* buf;
	yyscan_t scanner;
	int nerrors;

	// Define arguments.
	struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
	struct arg_str* command_arg = arg_str0("c", NULL, "<command>", "Run a single debugger command and exit with the result.");
	struct arg_file* symbols_file = arg_file0("s", "symbols", "<file>", "The file to load symbols from.");
	struct arg_file* input_file = arg_file0(NULL, NULL, "<file>", "The file to initially load.");
	struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization (for compatibility with older versions).");
	struct arg_lit* no_attach_mode = arg_lit0("n", "no-attachment", "Do not attach default devices when launched.");
	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[] = { show_help, no_attach_mode, command_arg, symbols_file, input_file, little_endian_mode, verbose, quiet, end };

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

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

		printf("syntax:\n    dtdb");
		arg_print_syntax(stderr, argtable, "\n");
		printf("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);

	// Register signal handler.
	signal(SIGINT, ddbg_sigint);

	// Initialize debugger.
	ddbg_init();

	// Initialize devices unless not requested.
	if (no_attach_mode->count == 0)
	{
		ddbg_attach(bfromcstr("clock"));
		ddbg_attach(bfromcstr("keyboard"));
		ddbg_attach(bfromcstr("lem1802"));
	}

	// Load file if filename is specified.
	if (input_file->count > 0)
	{
		ddbg_load(bfromcstr(input_file->filename[0]));
		ddbg_flash_vm();
	}
	if (symbols_file->count > 0)
		ddbg_load_symbols(bfromcstr(symbols_file->filename[0]));

	// If the user specified a command, execute only that
	// command and then continue.
	if (command_arg->count > 0)
	{
		ddbg_return_code = 1; // Default is failure.
		dbg_yylex_init(&scanner);
		dbg_yy_scan_string(command_arg->sval[0], scanner);
		dbg_yyparse(scanner);
		dbg_yylex_destroy(scanner);
		return ddbg_return_code;
	}

	// Create SDP thread if supported.
#ifdef FEATURE_SDP
	pthread_create(&sdp_thread, NULL, (void*)ddbg_sdp_thread, vm);
#endif

	// We always want to show the debugger start message.
	debug_setlevel(LEVEL_VERBOSE + verbose->count - quiet->count);
	version_print(bautofree(bfromcstr("Debugger")));
	debug_setlevel(LEVEL_DEFAULT + verbose->count - quiet->count);

	for (;;)
	{
		buf = readline("> ");
		add_history(buf);

		dbg_yylex_init(&scanner);
		dbg_yy_scan_string(buf, scanner);
		dbg_yyparse(scanner);
		dbg_yylex_destroy(scanner);
	}

	free(buf);

	return 0;
}