Beispiel #1
0
int dbg_lua_handle_raise(lua_State* L)
{
    struct dbg_state* state = dbg_lua_extract_state(L, 1);
    void* ud = dbg_lua_extract_state_ud(L, 1);
    dbg_lua_handle_hook(state, NULL, bautofree(bfromcstr(luaL_checkstring(L, 2))), luaL_optinteger(L, 3, 0));
    return 0;
}
Beispiel #2
0
int main(int argc, char* argv[])
{
	yyscan_t scanner;
	FILE* file;
	
	version_print(bautofree(bfromcstr("Preprocessor")));
	file = fopen(argv[1], "r");
	assert(file != NULL);
	ppfind_add_autopath(bautofree(bfromcstr(argv[1])));
	pp_yylex_init(&scanner);
	pp_yyset_out(stdout, scanner);
	pp_yyset_in(file, scanner);
	pp_yyparse(scanner);
	pp_yylex_destroy(scanner);
	return 0;
}
Beispiel #3
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");
}
Beispiel #4
0
void ddbg_step_into()
{
    vm->sleep_cycles = 0;
    vm_cycle(vm);

    // Handle custom Lua commands.
    dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("step")), 0);
}
Beispiel #5
0
void ppimpl_c_define_register(state_t* state)
{
    // Register #define directive.
    match_t* match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr("#define "));
    match->handler = define_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register macro terminator.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr("\1MACROTERMINATE\1"));
    match->handler = macro_term_handle;
    match->userdata = NULL;
    match->line_start_only = false;
    match->identifier_only = false;
    match->case_insensitive = false;
    ppimpl_register(state, match);
}
Beispiel #6
0
int main(int argc, char* argv[])
{
    struct errinfo* errval;

    if (argc != 2)
    {
        fprintf(stderr, "usage: dtpp lang < file\n");
        return 1;
    }

    osutil_setarg0(bautofree(bfromcstr(argv[0])));
    
    if (dsethalt())
    {
        errval = derrinfo();
        printf("error occurred while preprocessing:\n");
        printf(derrstr[errval->errid], errval->errdata);
        return 1;
    }

    ppimpl(bautofree(bfromcstr("<stdin>")), 0, bautofree(bfromcstr(argv[1])), has_input, input, output);
    return 0;
}
Beispiel #7
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);
}
Beispiel #8
0
int main(int argc, char* argv[])
{
    bstring ldargs = bfromcstr("");
    int i, result;
    unsigned int match = 0, unmatch = 0;
    char ca, ce;
    BFILE* expect;
    BFILE* actual;

    // Define arguments.
    struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
    struct arg_lit* gen_relocatable = arg_lit0("r", "relocatable", "Generate relocatable code.");
    struct arg_lit* gen_intermediate = arg_lit0("i", "intermediate", "Generate intermediate code for use with the linker.");
    struct arg_lit* little_endian_mode = arg_lit0(NULL, "little-endian", "Use little endian serialization.");
    struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input assembly file.");
    struct arg_file* expect_file = arg_file0("e", "expect", "<file>", "The output file that contains expected output.");
    struct arg_file* actual_file = arg_file1("a", "actual", "<file>", "The output file where actual output will be placed.");
    struct arg_file* symbols_file = arg_file0("s", "debug-symbols", "<file>", "The debugging symbol output file.");
    struct arg_lit* fail_opt = arg_lit0("f", "fail", "The assembler is expected to fail and the actual output file should not exist on completion.");
    struct arg_file* path = arg_file1("p", NULL, "<path>", "The path to the assembler.");
    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, gen_relocatable, gen_intermediate, little_endian_mode, symbols_file, input_file, expect_file, actual_file, fail_opt, path, verbose, quiet, end };

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

    version_print(bautofree(bfromcstr("Assembler Test Driver")));
    if (nerrors != 0 || show_help->count != 0 || (fail_opt->count == 0 && (expect_file->count == 0 || actual_file->count == 0)))
    {
        if (show_help->count != 0 && fail_opt->count == 0 && (expect_file->count == 0 || actual_file->count == 0))
            printd(LEVEL_ERROR, "error: you must provide either -f or -e and -a.\n");
        if (show_help->count != 0)
            arg_print_errors(stderr, end, "testasm");

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

    // Generate the argument list for the assembler.
    ldargs = bfromcstr(path->filename[0]);
    binsertch(ldargs, 0, 1, '"');
    bconchar(ldargs, '"');
    bconchar(ldargs, ' ');

    // Verbosity options.
    if (verbose->count > 0)
    {
        bconchar(ldargs, '-');
        for (i = 0; i < verbose->count; i++) bconchar(ldargs, 'v');
        bconchar(ldargs, ' ');
    }
    if (quiet->count > 0)
    {
        bconchar(ldargs, '-');
        for (i = 0; i < quiet->count; i++) bconchar(ldargs, 'q');
        bconchar(ldargs, ' ');
    }

    // Literal options.
    if (gen_relocatable->count > 0)
    {
        bconchar(ldargs, '-');
        for (i = 0; i < gen_relocatable->count; i++) bconchar(ldargs, 'r');
        bconchar(ldargs, ' ');
    }
    if (gen_intermediate->count > 0)
    {
        bconchar(ldargs, '-');
        for (i = 0; i < gen_intermediate->count; i++) bconchar(ldargs, 'i');
        bconchar(ldargs, ' ');
    }
    if (little_endian_mode->count > 0)
    {
        for (i = 0; i < little_endian_mode->count; i++)
            bcatcstr(ldargs, "--little-endian ");
    }

    // Unlink the actual file so that if we are expecting
    // failure, we won't return incorrectly.
    unlink(actual_file->filename[0]);

    // Output file.
    bcatcstr(ldargs, "-o \"");
    bcatcstr(ldargs, actual_file->filename[0]);
    bcatcstr(ldargs, "\" ");

    // Input file.
    bcatcstr(ldargs, "\"");
    bcatcstr(ldargs, input_file->filename[0]);
    bcatcstr(ldargs, "\" ");

    // Windows needs the whole command wrapped in quotes and slashes to be correct.
    // See http://stackoverflow.com/questions/2642551/windows-c-system-call-with-spaces-in-command.
#ifdef _WIN32
    binsertch(ldargs, 0, 1, '"');
    bconchar(ldargs, '"');
#endif

    // Now run the assembler!
    result = system(ldargs->data);
    if (result != 0 && fail_opt->count == 0)
    {
        // Assembler returned error exit code.
        printd(LEVEL_ERROR, "error: expected success but assembler returned non-zero exit code (%i).\n", result);
        return 1;
    }
    else if (result == 0 && fail_opt->count >= 1)
    {
        // Assembler returned zero when failure was expected.
        printd(LEVEL_ERROR, "error: expected failure but assembler returned zero exit code.\n");
        return 1;
    }
    else if (result != 0 && fail_opt->count >= 1)
    {
        // Assembler failed and we expected it to.  Return success only
        // if the output file does not exist.
        actual = bfopen(actual_file->filename[0], "rb");
        if (actual != NULL)
        {
            printd(LEVEL_ERROR, "error: expected failure but actual output file exists.\n");
            bfclose(actual);
            return 1;
        }
        return 0;
    }

    // Open expect data.
    expect = bfopen(expect_file->filename[0], "rb");
    if (expect == NULL)
    {
        // The expect file was not provided.
        printd(LEVEL_ERROR, "error: path to expect file does not exist.\n");
        return 1;
    }

    // Open actual data.
    actual = bfopen(actual_file->filename[0], "rb");
    if (actual == NULL)
    {
        // The expect file was not provided.
        bfclose(expect);
        printd(LEVEL_ERROR, "error: expected data but actual output file does not exist after running assembler.\n");
        return 1;
    }

    // Now compare raw bytes.
    while (true)
    {
        if (!bfeof(actual) && !bfeof(expect))
        {
            ca = bfgetc(actual);
            ce = bfgetc(expect);
            if (ca == ce)
                match++;
            else
            {
                printd(LEVEL_WARNING, "warning: byte at 0x%04X is different (got 0x%02X, expected 0x%02X)!\n", bftell(actual), ca, ce);
                unmatch++;
            }
        }
        else if (!bfeof(actual))
        {
            ca = bfgetc(actual);
            printd(LEVEL_ERROR, "error: actual output contained trailing byte 0x%02X.\n", (unsigned char)ca);
            unmatch++;
        }
        else if (!bfeof(expect))
        {
            ce = bfgetc(expect);
            printd(LEVEL_ERROR, "error: expected actual output to contain 0x%02X.\n", (unsigned char)ce);
            unmatch++;
        }
        else
            break;
    }
    if (unmatch > 0)
    {
        printd(LEVEL_ERROR, "error: actual output differs from expected output in content (%f%%, %i bytes different).\n", 100.f / (unmatch + match) * unmatch, unmatch);
        if (bftell(actual) != bftell(expect))
            printd(LEVEL_ERROR, "error: actual output differs from expected output in length (%i bytes larger).\n", bftell(actual) - bftell(expect));
        bfclose(actual);
        bfclose(expect);
        return 1;
    }

    // Close files and delete actual because we have
    // succeeded.
    bfclose(actual);
    bfclose(expect);
    unlink(actual_file->filename[0]);

    return 0;
}
Beispiel #9
0
int main(int argc, char* argv[])
{
	// Define arguments.
	struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
	struct arg_str* type_assembler = arg_str0("t", NULL, "<type>", "The type of assembler to output for.");
	struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file (or - to read from standard input).");
	struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output).");
	// 20 is maxcount for include directories, this has to be set to some constant number.
	struct arg_file* include_dirs = arg_filen("I", NULL, "<directory>", 0, 20, "Adds the directory <dir> to the directories to be searched for header files.");
	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[] = { output_file, show_help, type_assembler, include_dirs, input_file, verbose, quiet, end };

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

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

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

	// Run the preprocessor.
	ppfind_add_path(bautofree(bfromcstr(".")));
	ppfind_add_path(bautofree(bfromcstr("include")));
	ppfind_add_autopath(bautofree(bfromcstr(input_file->filename[0])));
	for (int i = 0; i < include_dirs->count; ++i)
		ppfind_add_path(bautofree(bfromcstr(include_dirs->filename[i])));
	bstring pp_result_name = pp_do(bautofree(bfromcstr(input_file->filename[0])));

	if (pp_result_name == NULL)
	{
		fprintf(stderr, "compiler: invalid result returned from preprocessor.\n");
		pp_cleanup(bautofree(pp_result_name));
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// Parse C.
	yyout = stderr;
	yyin = fopen((const char*)(pp_result_name->data), "r");

	if (yyin == NULL)
	{
		pp_cleanup(bautofree(pp_result_name));
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	yyparse();

	if (yyin != stdin)
		fclose(yyin);

	pp_cleanup(bautofree(pp_result_name));

	if (program == NULL)
	{
		std::cerr << "An error occurred while compiling." << std::endl;
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// Assembler type.
	const char* asmtype = "toolchain";

	if (type_assembler->count > 0)
		asmtype = type_assembler->sval[0];

	// Initially save to a temporary file.
	std::string temp = std::string(tempnam(".", "cc."));

	// Generate assembly using the AST.
	try
	{
		AsmGenerator generator(asmtype);
		AsmBlock* block = program->compile(generator);

		std::ofstream output(temp.c_str(), std::ios::out | std::ios::trunc);
		if (output.bad() || output.fail())
		{
			printd(LEVEL_ERROR, "compiler: temporary file not writable.\n");
			arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
			return 1;
		}
		output << *block << std::endl;
		output.close();

		delete block;
	}
	catch (CompilerException* ex)
	{
		std::string msg = ex->getMessage();
		std::cerr << "An error occurred while compiling." << std::endl;
		std::cerr << msg << std::endl;
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// Re-open the temporary file for reading.
	std::ifstream input(temp.c_str(), std::ios::in);
	if (input.bad() || input.fail())
	{
		printd(LEVEL_ERROR, "compiler: temporary file not readable.\n");
		arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
		return 1;
	}

	// Open the output file.
	std::ostream* output;
	if (strcmp(output_file->filename[0], "-") != 0)
	{
		// Write to file.
		output = new std::ofstream(output_file->filename[0], std::ios::out | std::ios::trunc);

		if (output->bad() || output->fail())
		{
			printd(LEVEL_ERROR, "compiler: output file not readable.\n");
			arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
			return 1;
		}
	}
	else
	{
		// Set output to cout.
		output = &std::cout;
	}

	// Copy data.
	std::copy(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(*output));

	// Close files and delete temporary.
	if (strcmp(output_file->filename[0], "-") != 0)
	{
		((std::ofstream*)output)->close();
		delete output;
	}
	input.close();
	unlink(temp.c_str());

	arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
	return 0;
}
Beispiel #10
0
void ddbg_interrupt_hook(vm_t* vm, uint16_t pos, void* ud)
{
    // Handle custom Lua commands.
    dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("interrupt")), pos);
}
Beispiel #11
0
uint16_t aout_write(FILE* out, bool relocatable, bool intermediate)
{
	struct aout_byte* current_outer;
	struct aout_byte* current_inner;
	struct lprov_entry* linker_provided = NULL;
	struct lprov_entry* linker_required = NULL;
	struct lprov_entry* linker_adjustment = NULL;
	struct lprov_entry* linker_section = NULL;
	struct lprov_entry* linker_output = NULL;
	struct lprov_entry* linker_temp = NULL;
	uint32_t mem_index, out_index;
	uint16_t inst;
	BFILE* temp = NULL;
	bstring bname, ename;
	uint16_t eaddr;
	bool did_find;
	bool shown_expr_warning = false;
	bool has_output = false;

	// Initialize out our extension table.
	code_offset += textn_init(start);

	// If relocatable, initialize out our relocation table.
	if (relocatable)
		code_offset += treloc_init(start);

	// First go through and evaluate all expressions that need to be.
	current_outer = start;
	out_index = code_offset;
	while (current_outer != NULL)
	{
		if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN)
		{
			// Adjust memory address.
			out_index = current_outer->opcode;
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_SECTION)
		{
			assert(current_outer->label != NULL);

			// We're exporting the current address as the beginning
			// of a section.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Check to make sure outputs haven't previously been emitted.
			if (has_output)
				ahalt(ERR_OUTPUT_BEFORE_SECTION, NULL);

			// Create linker entry.
			linker_temp = lprov_create(current_outer->label, out_index);
			linker_temp->next = linker_section;
			linker_section = linker_temp;
			printd(LEVEL_VERBOSE, "LINK SECTION %s -> 0x%04X\n", current_outer->label, out_index);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_OUTPUT)
		{
			assert(current_outer->label != NULL);

			// We're exporting the current address as the beginning
			// of a section.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Create linker entry.
			has_output = true;
			linker_temp = lprov_create(current_outer->label, out_index);
			linker_temp->next = linker_output;
			linker_output = linker_temp;
			printd(LEVEL_VERBOSE, "LINK OUTPUT 0x%04X -> %s\n", out_index, current_outer->label);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_EXPORT)
		{
			assert(current_outer->label != NULL);

			// We're exporting the address of this label in the
			// object table.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Resolve label position.
			ename = bfromcstr(current_outer->label);
			eaddr = aout_get_label_address(ename);
			bdestroy(ename);

			// Create linker entry.
			linker_temp = lprov_create(current_outer->label, eaddr);
			linker_temp->next = linker_provided;
			linker_provided = linker_temp;
			printd(LEVEL_VERBOSE, "LINK REPLACE %s -> 0x%04X\n", current_outer->label, eaddr);
		}
		else if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->expr != NULL)
		{
			if (current_outer->expr->type != EXPR_LABEL)
			{
				// This is either just a number or a more complicated expression, so
				// evaluate it using the preprocessor expression engine.
				if ((relocatable || intermediate) && !shown_expr_warning)
				{
					printd(LEVEL_WARNING, "warning: expressions will not be adjusted at link or relocation time.\n");
					printd(LEVEL_WARNING, "		ensure labels are not used as part of expressions.\n");
					shown_expr_warning = true;
				}
				current_outer->raw_used = true;
				current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler);
				expr_delete(current_outer->expr);
				current_outer->expr = NULL;
			}
			else
			{
				// If this is just a label, we can handle it directly (this allows
				// us to handle imported labels in intermediate code).
				current_inner = start;
				mem_index = code_offset;
				did_find = false;

				// Search for .IMPORT directives first.
				while (current_inner != NULL)
				{
					if (current_inner->type == AOUT_TYPE_METADATA_ORIGIN)
					{
						// Adjust memory address.
						mem_index = current_inner->opcode;
					}
					else if (current_inner->type == AOUT_TYPE_METADATA_IMPORT)
					{
						// An imported label (we don't need to adjust
						// memory index because the existance of this type
						// of entry doesn't affect executable size).
						if (!intermediate)
							ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

						assert(current_outer->expr->data != NULL);
						if (strcmp(current_inner->label, ((bstring)current_outer->expr->data)->data) == 0)
						{
							// We don't actually know our position yet;
							// that will be handled by the linker!
							current_outer->raw = 0xFFFF;
							expr_delete(current_outer->expr);
							current_outer->expr = NULL;
							linker_temp = lprov_create(current_inner->label, out_index);
							linker_temp->next = linker_required;
							linker_required = linker_temp;
							printd(LEVEL_VERBOSE, "LINK REPLACE 0x%04X -> %s\n", out_index, current_inner->label);
							did_find = true;
							break;
						}
					}

					// Goto next.
					current_inner = current_inner->next;
				}

				// If it wasn't found in the .IMPORT directives, try searching
				// labels directly using the expression engine.
				if (!did_find)
				{
					// Replace the label position.
					current_outer->raw_used = true;
					current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler);
					expr_delete(current_outer->expr);
					current_outer->expr = NULL;
					did_find = true;

					// We also need to add this entry to the adjustment
					// table for the linker since it also needs to adjust
					// internal label jumps in files when it concatenates
					// all of the object code together.
					linker_temp = lprov_create(NULL, out_index);
					linker_temp->next = linker_adjustment;
					linker_adjustment = linker_temp;
					printd(LEVEL_VERBOSE, "LINK ADJUST 0x%04X\n", out_index);
				}
			}
		}

		if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->label == NULL)
			out_index += 1;

		current_outer = current_outer->next;
	}

	// If intermediate, we need to write out our linker table
	// as the absolute first thing in the file.
	if (intermediate)
	{
		fwrite(ldata_objfmt, 1, strlen(ldata_objfmt) + 1, out);
		objfile_save(out, linker_provided, linker_required, linker_adjustment, linker_section, linker_output);

		// Adjust the "true origin" for .ORIGIN directivies because
		// the linker table won't exist in the final result when
		// linked.
		true_origin = (uint16_t)ftell(out);
	}

	// Write out our extension table.
	textn_write(out);

	// If relocatable, write out our relocation table.
	if (relocatable)
		treloc_write(out);

	// Now write to the file.
	current_outer = start;

	while (current_outer != NULL)
	{
		if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN)
		{
			// Adjust origin.
			fseek(out, true_origin + current_outer->opcode * 2 /* double because the number is in words, not bytes */, SEEK_SET);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_INCBIN)
		{
			// Include binary file.
			bname = ppfind_locate(bautofree(bfromcstr(current_outer->label)));

			if (bname == NULL)
				ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label);

			temp = bfopen((const char*)(bname->data), "rb");

			if (temp == NULL)
				ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label);

			// Copy binary data.
			while (!bfeof(temp))
			{
				// TODO: This could be faster if we didn't do it character
				// by character.
				fputc(bfgetc(temp), out);
			}

			// Finalize.
			bfclose(temp);
			bdestroy(bname);
		}
		else if (current_outer->type == AOUT_TYPE_NORMAL)
		{
			// Update the debugging symbol.
			dbgfmt_update_symbol_list(&current_outer->symbols, (uint16_t)((ftell(out) - true_origin) / 2));

			// Normal output.
			if (current_outer->raw_used == true)
			{
				inst = current_outer->raw;
				iwrite(&inst, out);
			}
			else if (current_outer->label == NULL)
			{
				inst = INSTRUCTION_CREATE(current_outer->opcode, current_outer->a, current_outer->b);
				iwrite(&inst, out);
			}
		}

		// Goto next in linked list.
		current_outer = current_outer->next;
	}

	fflush(out);

	return (uint16_t)((ftell(out) - true_origin) / 2);
}
Beispiel #12
0
int main(int argc, char* argv[])
{
    CURL* curl;
    bstring command;
    bstring name;
    bstring modpath;
    int all;

    // Define arguments.
    struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
    struct arg_str* cmdopt = arg_str1(NULL, NULL, "<command>", "The command; either 'search', 'install', 'uninstall', 'enable' or 'disable'.");
    struct arg_str* nameopt = arg_str0(NULL, NULL, "<name>", "The name of the module to search for, install, uninstall, enable or disable.");
    struct arg_lit* all_flag = arg_lit0("a", "all", "Apply this command to all available / installed modules.");
    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, cmdopt, all_flag, nameopt, verbose, quiet, end };

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

    if (nerrors != 0 || show_help->count != 0 || (all_flag->count == 0 && nameopt->count == 0))
    {
        if (all_flag->count == 0 && nameopt->count == 0)
            printd(LEVEL_ERROR, "error: must have either module name or -a.");
        if (show_help->count != 0)
            arg_print_errors(stderr, end, "mm");

        fprintf(stderr, "syntax:\n    dtmm");
        arg_print_syntax(stderr, argtable, "\n");
        fprintf(stderr, "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("Module Manager")));

    // Set argument 0 and convert parameters.
    osutil_setarg0(bautofree(bfromcstr(argv[0])));
    command = bfromcstr(cmdopt->sval[0]);
    name = bfromcstr(nameopt->sval[0]);

    // Initialize curl or exit.
    curl = curl_easy_init();
    if (!curl)
    {
        printd(LEVEL_ERROR, "unable to initialize curl.\n");
        return 1;
    }

    // Ensure module path exists.
    modpath = osutil_getmodulepath();
    if (modpath == NULL)
    {
        printd(LEVEL_ERROR, "module path does not exist (searched TOOLCHAIN_MODULES and modules/).\n");
        return 1;
    }
    bdestroy(modpath);

    // Convert all flag.
    all = (all_flag->count > 0);

    // If all is set, set the name back to "".
    if (all)
        bassigncstr(name, "");

    // If the name is "all" or "*", handle this as the all
    // boolean flag.
    if (biseqcstr(name, "all") || biseqcstr(name, "*"))
    {
        bassigncstr(name, "");
        all = 1;
        printd(LEVEL_WARNING, "treating name as -a (all) flag");
    }

    if (biseqcstrcaseless(command, "search") || biseqcstrcaseless(command, "se"))
        return do_search(curl, name, all);
    else if (biseqcstrcaseless(command, "install") || biseqcstrcaseless(command, "in"))
    {
        if (all)
            return do_install_all(curl);
        else
            return do_install(curl, name);
    }
    else if (biseqcstrcaseless(command, "uninstall") || biseqcstrcaseless(command, "rm"))
    {
        if (all)
            return do_uninstall_all(curl);
        else
            return do_uninstall(curl, name);
    }
    else if (biseqcstrcaseless(command, "enable") || biseqcstrcaseless(command, "en"))
    {
        if (all)
            return do_enable_all(curl);
        else
            return do_enable(curl, name);
    }
    else if (biseqcstrcaseless(command, "disable") || biseqcstrcaseless(command, "di") || biseqcstrcaseless(command, "dis"))
    {
        if (all)
            return do_disable_all(curl);
        else
            return do_disable(curl, name);
    }
    else
    {
        printd(LEVEL_ERROR, "unknown command (must be search, install, uninstall, enable or disable).");
        return 1;
    }

    return 0;
}
Beispiel #13
0
void ddbg_precycle_hook(vm_t* vm, uint16_t pos, void* ud)
{
    unsigned int i = 0;
    struct breakpoint* bk;
    uint16_t op, a, b;

    // Handle any symbols that are at this cycle.
    list_t* symbols = ddbg_get_symbols(vm->pc);
    list_iterator_start(symbols);
    while (list_iterator_hasnext(symbols))
        dbg_lua_handle_hook_symbol(&lstate, NULL, bautofree((bstring)list_iterator_next(symbols)));
    list_iterator_stop(symbols);
    list_empty(symbols);
    free(symbols);

    // Handle custom Lua commands.
    dbg_lua_handle_hook(&lstate, NULL, bautofree(bfromcstr("precycle")), pos);

    // Check to see if Lua halted the VM and return if it did.
    if (vm->halted)
        return;

    // Handle breakpoints.
    if (!ignore_next_breakpoint)
    {
        for (i = 0; i < list_size(&breakpoints); i++)
        {
            bk = (struct breakpoint*)list_get_at(&breakpoints, i);

            if (vm->pc == bk->addr)
            {
                vm->halted = true;
                ignore_next_breakpoint = true;
                vm_hook_break(vm); // Required for UI to update correctly.
                if (bk->temporary)
                    list_delete_at(&breakpoints, i--);
                if (!bk->silent)
                    ddbg_disassemble(max_int32((int32_t)vm->pc - 10, 0x0), min_int32((int32_t)vm->pc + 10, 0x10000) - vm->pc);
                printd(LEVEL_DEFAULT, "Breakpoint hit at 0x%04X.\n", bk->addr);
                return;
            }
        }
    }
    ignore_next_breakpoint = false;

    // Handle backtrace.
    op = INSTRUCTION_GET_OP(vm->ram[vm->pc]);
    a = INSTRUCTION_GET_A(vm->ram[vm->pc]);
    b = INSTRUCTION_GET_B(vm->ram[vm->pc]);
    if ((op == OP_SET && b == PC) || (op == OP_NONBASIC && b == NBOP_JSR))
    {
        // FIXME: This doesn't handle every valid value correctly..
        if (a == PUSH_POP)
            list_delete_at(&backtrace, list_size(&backtrace) - 1);
        else if (a == NXT_LIT)
        {
            printd(LEVEL_DEBUG, "jumping literally from 0x%04X to 0x%04X (0x%04X).\n", vm->pc, vm->ram[vm->pc + 1], vm->pc + 1);
            list_append(&backtrace, backtrace_entry_create(vm->pc, vm->ram[vm->pc + 1]));
        }
        else if (a == NXT)
        {
            //list_append(&backtrace, backtrace_entry_create(vm->pc, vm->ram[vm->ram[vm->pc+1]]));
        }
        else
        {
            // Unhandled.
            printd(LEVEL_DEBUG, "warning: unhandled backtrace jump occurred.\n");
        }
    }
}
Beispiel #14
0
static void macro_handle(state_t* state, match_t* match, bool* reprocess)
{
    bstring name;
    bstring temp;
    list_t parameters;
    list_t arguments;
    bool getting_name = true;
    bool getting_parameters = false;
    bool getting_arguments = false;
    struct replace_info* info = match->userdata;
    int i = 0;
    int argument_brackets = 0;
    char c;
    char* start_loc;
    match_t* new_match;
    struct replace_info* new_info;

    // Parse the parameters out of the name.
    list_init(&parameters);
    temp = bfromcstr("");
    for (i = 0; i < blength(info->full); i++)
    {
        c = info->full->data[i];
        if (getting_name)
        {
            if (c == '(')
            {
                getting_name = false;
                getting_parameters = true;
                name = bstrcpy(temp);
                bassigncstr(temp, "");
            }
            else
                bconchar(temp, c);
        }
        else if (getting_parameters)
        {
            if (c == ',' || c == ')')
            {
                btrimws(temp);
                list_append(&parameters, bstrcpy(temp));
                bassigncstr(temp, "");
                if (c == ')')
                {
                    getting_parameters = false;
                    break;
                }
            }
            else
                bconchar(temp, c);
        }
    }

    // Attempt to accept an open bracket.
    c = ppimpl_get_input(state);
    while (c == '\1')
    {
        // Consume macro termination.
        i = 0;
        while (i < strlen("\1MACROTERMINATE\1"))
        {
            if (c != "\1MACROTERMINATE\1"[i++])
                dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state));
            c = ppimpl_get_input(state);
        }
        ppimpl_pop_scope(state);
    }
    if (c != '(')
        dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state));
    
    // Read arguments.
    getting_arguments = true;
    list_init(&arguments);
    start_loc = ppimpl_get_location(state);
    bassigncstr(temp, "");
    while (ppimpl_has_input(state) && getting_arguments)
    {
        c = ppimpl_get_input(state);

        if (c == '(')
        {
            argument_brackets++;
            bconchar(temp, c);
        }
        else if (c == ')' && argument_brackets != 0)
        {
            argument_brackets--;
            bconchar(temp, c);
        }
        else if (c == ')' && argument_brackets == 0)
        {
            list_append(&arguments, bstrcpy(temp));
            bassigncstr(temp, "");
            getting_arguments = false;
            break;
        }
        else if (c == ',' && argument_brackets == 0)
        {
            list_append(&arguments, bstrcpy(temp));
            bassigncstr(temp, "");
        }
        else
            bconchar(temp, c);
    }
    if (getting_arguments)
        dhalt(ERR_PP_NO_TERMINATING_BRACKET, start_loc);

    // Check to see if the argument count is correct.
    if (list_size(&arguments) > list_size(&parameters))
        dhalt(ERR_PP_TOO_MANY_PARAMETERS, start_loc);
    else if (list_size(&arguments) < list_size(&parameters))
        dhalt(ERR_PP_NOT_ENOUGH_PARAMETERS, start_loc);
    free(start_loc);

    // Create a new scope for macro evaluation.
    ppimpl_push_scope(state, true);

    // Define the new handlers.
    for (i = 0; i < list_size(&parameters); i++)
    {
        new_info = malloc(sizeof(struct replace_info));
        new_info->full = list_get_at(&parameters, i);
        new_info->replacement = list_get_at(&arguments, i);
        if (biseq(new_info->full, new_info->replacement))
        {
            free(new_info);
            continue;
        }
        new_match = malloc(sizeof(match_t));
        new_match->text = bautofree(list_get_at(&parameters, i));
        new_match->handler = replace_handle;
        new_match->line_start_only = false;
        new_match->identifier_only = true;
        new_match->userdata = new_info;
        new_match->case_insensitive = false;
        ppimpl_register(state, new_match);
    }
    
    // Print out the macro evaluation and terminator.
    ppimpl_printf(state, "%s\1MACROTERMINATE\1", info->replacement->data);
}
Beispiel #15
0
int main(int argc, char* argv[])
{
	// Define our variables.
	FILE* in;
	FILE* out;
	int nerrors, i;
	char* test;
	uint16_t offset, current, store, mem_index;
	struct lprov_entry* required = NULL;
	struct lprov_entry* provided = NULL;
	struct lprov_entry* adjustment = NULL;
	struct lprov_entry* temp = NULL;

	// Define arguments.
	struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
	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_end* end = arg_end(20);
	void* argtable[] = { show_help, input_files, output_file, 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");

		printf("syntax:\n    linker");
		arg_print_syntax(stdout, argtable, "\n");
		printf("options:\n");
		arg_print_glossary(stdout, argtable, "	  %-25s %s\n");
		return 1;
	}

	// Open the output file for writing.
	out = fopen(output_file->filename[0], "wb");

	if (out == NULL)
	{
		// Handle the error.
		fprintf(stderr, "linker: unable to write to output file.\n");
		return 1;
	}

	// We initially need to get a list of ALL provided
	// labels before we can start replacing them.
	offset = 0;

	for (i = 0; i < input_files->count; i++)
	{
		// Open the input file.
		in = fopen(input_files->filename[i], "rb");

		if (in == NULL)
		{
			// Handle the error.
			fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]);
			fclose(out);
			return 1;
		}

		// Is this the object format?
		test = malloc(strlen(ldata_objfmt) + 1);
		memset(test, 0, strlen(ldata_objfmt) + 1);
		fread(test, 1, strlen(ldata_objfmt), in);
		fseek(in, 1, SEEK_CUR);

		if (strcmp(test, ldata_objfmt) != 0)
		{
			// Handle the error.
			fprintf(stderr, "linker: input file '%s' is not in object format 1.0.\n", input_files->filename[i]);
			fclose(in);
			fclose(out);
			return 1;
		}

		free(test);

		// Load only the provided label entries into memory.
		objfile_load(input_files->filename[i], in, &offset, &provided, NULL, NULL);

		// Close the file.
		fclose(in);
	}

	// Now we can start replacing the labels with the provided values
	// since we have ALL of the provided labels available.
	offset = 0;

	for (i = 0; i < input_files->count; i++)
	{
		// Open the input file.
		in = fopen(input_files->filename[i], "rb");

		if (in == NULL)
		{
			// Handle the error.
			fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]);
			fclose(out);
			return 1;
		}

		// Skip over the object format label; we already tested
		// for this in phase 1.
		fseek(in, strlen(ldata_objfmt) + 1, SEEK_CUR);

		// Load only the required and adjustment entries into memory.
		current = offset;
		objfile_load(input_files->filename[i], in, &offset, NULL, &required, &adjustment);

		// Copy all of the input file's data into the output
		// file, word by word.
		mem_index = 0;
		fprintf(stderr, "BEGIN %s\n", input_files->filename[i]);

		while (!feof(in))
		{
			// Read a word.
			fread(&store, sizeof(uint16_t), 1, in);

			// For some strange reason, the last two bytes get
			// written twice, as if it's only EOF after you
			// attempt to read past the end again.	I'm not sure
			// why the semantics are like this, but checking again
			// for EOF here prevents us writing double.
			if (feof(in))
				break;

			// Check to see if we need to do something with this
			// word, such as adjusting it.
			if (lprov_find_by_address(adjustment, mem_index) != NULL)
			{
				// We need to adjust this word by the offset.
				store += current;
				fprintf(stderr, "ADJUSTED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store - current, store);
			}

			// Check to see if we need to resolve this word into
			// an actual address because it was imported.
			temp = lprov_find_by_address(required, mem_index);

			if (temp != NULL)
			{
				// Find the position we should change this to.
				temp = lprov_find_by_label(provided, temp->label);

				// We need to set this word to the proper location.
				fprintf(stderr, "RESOLVED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store, temp->address);
				store = temp->address;
			}

			// Now write the (potentially modified) word to the
			// output.
			fprintf(stderr, " >> WRITE 0x%04X\n", store);
			fwrite(&store, sizeof(uint16_t), 1, out);

			// Increment memory position.
			mem_index++;
		}

		// Close the file.
		fclose(in);

		// Reset and free the required and adjustment linked list.
		// FIXME: Actually free the lists!
		required = NULL;
		adjustment = NULL;
	}

	// Close file.
	fprintf(stderr, "linker: completed successfully.\n", input_files->filename[i]);
	fclose(out);

	return 0;
}
Beispiel #16
0
void process_line(struct ast_node_line* line)
{
	struct instruction_mapping* insttype;
	struct process_parameters_results ppresults;
	struct process_parameter_results dparam;
	struct ast_node_parameter* dcurrent;
	uint32_t dchrproc;
	uint16_t i, flimit, fchar, opos;

	// Change depending on the type of line.
	switch (line->type)
	{
		case type_keyword:
			switch (line->keyword)
			{
				case BOUNDARY:
					fprintf(stderr, ".BOUNDARY");

					// Emit safety boundary of 16 NULL words.
					for (i = 0; i < 16; i += 1)
						aout_emit(aout_create_raw(0));

					break;

				case FILL:
					fprintf(stderr, ".FILL");

					// Emit N words with value X
					flimit = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					fchar = expr_evaluate(line->keyword_data_expr_2, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					for (i = 0; i < flimit; i++)
						aout_emit(aout_create_raw(fchar));

					break;

				case EXTENSION:
					fprintf(stderr, ".EXTENSION %s", line->keyword_data_string);

					// Emit extension metadata.
					aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case INCBIN:
					fprintf(stderr, ".INCBIN %s", line->keyword_data_string);

					// Emit binary include metadata.
					aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case ORIGIN:
					opos = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					fprintf(stderr, ".ORIGIN 0x%04X", opos);

					// Emit origin set metadata.
					aout_emit(aout_create_metadata_origin(opos));

					break;

				case EXPORT:
					fprintf(stderr, ".EXPORT %s", line->keyword_data_string);

					// Emit export metadata.
					aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case IMPORT:
					fprintf(stderr, ".IMPORT %s", line->keyword_data_string);

					// Emit export metadata.
					aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0')));

					break;

				default:
					fprintf(stderr, "\n");
					ahalt(ERR_UNSUPPORTED_KEYWORD, NULL);
			}

			fprintf(stderr, "\n");
			break;

		case type_instruction:

			// Check to see if this is DAT.
			if (strcmp(line->instruction->instruction, "DAT") == 0)
			{
				// Handle data.
				fprintf(stderr, "EMIT DAT");

				// Process parameters as data.
				reverse_parameters(line->instruction->parameters);
				dcurrent = line->instruction->parameters->last;

				while (dcurrent != NULL)
				{
					// Process parameter normally.
					dparam = process_parameter(dcurrent);

					// Output depending on what kind of parameter it was.
					if (dparam.v_label != NULL) // If this is a label, output something that we need to replace.
						aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label)))));
					else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it.
					{
						fprintf(stderr, " \"%s\"", dparam.v_raw->data);

						for (dchrproc = 0; dchrproc < blength(dparam.v_raw); dchrproc++)
							aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc]));
					}
					else if (dparam.v_extra_used == true) // Just a single address.
						aout_emit(aout_create_expr(dparam.v_extra));
					else // Something that isn't handled by DAT.
					{
						fprintf(stderr, "\n");
						ahalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL);
					}

					dcurrent = dcurrent->prev;
				}
			}
			else
			{
				// Handle instruction.
				insttype = get_instruction_by_name(line->instruction->instruction);

				if (insttype == NULL)
					ahalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction);

				fprintf(stderr, "EMIT %s", insttype->name);

				// Process parameters normally.
				ppresults = process_parameters(line->instruction->parameters);

				// Force the parameter value to be NXT if it's a label.
				if (ppresults.a_label != NULL) ppresults.a = NXT_LIT;

				if (ppresults.b_label != NULL) ppresults.b = NXT_LIT;

				if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT;

				if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT;

				// Output the initial opcode.
				if (insttype->opcode != OP_NONBASIC)
					aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b));
				else
					aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a));

				// If the parameter is a label or requires an extra word, output them.
				if (ppresults.b_label != NULL)
					aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label)))));
				else if (ppresults.b_extra_used)
					aout_emit(aout_create_expr(ppresults.b_extra));

				if (ppresults.a_label != NULL)
					aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label)))));
				else if (ppresults.a_extra_used)
					aout_emit(aout_create_expr(ppresults.a_extra));

			}

			fprintf(stderr, "\n");
			break;

		case type_label:
			// Handle label definition.
			fprintf(stderr, ":%s\n", line->label->name);
			aout_emit(aout_create_label(line->label->name));
			break;
	}
}
Beispiel #17
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;
}
Beispiel #18
0
void process_line(struct ast_node_line* line)
{
    struct instruction_mapping* insttype;
    struct process_parameters_results ppresults;
    struct process_parameter_results dparam;
    struct ast_node_parameter* dcurrent;
    uint32_t dchrproc;
    uint16_t i, flimit, fchar, opos;
    struct aout_byte* result = NULL;
    struct dbg_sym* newsym;

    // Change depending on the type of line.
    switch (line->type)
    {
        case type_keyword:
            switch (line->keyword)
            {
                case SYMBOL:
                    printd(LEVEL_VERBOSE, ".SYMBOL %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit debugging symbol.
                    list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_STRING, dbgfmt_create_symbol_string(line->keyword_data_string, DBGFMT_UNDETERMINED)));

                    break;

                case SECTION:
                    printd(LEVEL_VERBOSE, ".SECTION %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit section metadata.
                    aout_emit(aout_create_metadata_section(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case OUTPUT:
                    printd(LEVEL_VERBOSE, ".OUTPUT %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit output metadata.
                    aout_emit(aout_create_metadata_output(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case BOUNDARY:
                    printd(LEVEL_VERBOSE, ".BOUNDARY");

                    // Emit safety boundary of 16 NULL words.
                    for (i = 0; i < 16; i += 1)
                        aout_emit(aout_create_raw(0));

                    break;

                case FILL:
                    printd(LEVEL_VERBOSE, ".FILL");

                    if (line->keyword_data_expr_1 == NULL || line->keyword_data_expr_2 == NULL)
                    {
                        if (line->keyword_data_string != NULL)
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data);
                        else
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, "");
                    }

                    // Emit N words with value X
                    flimit = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler);
                    fchar = expr_evaluate(line->keyword_data_expr_2, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler);
                    for (i = 0; i < flimit; i++)
                        aout_emit(aout_create_raw(fchar));

                    break;

                case EXTENSION:
                    printd(LEVEL_VERBOSE, ".EXTENSION %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit extension metadata.
                    aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case INCBIN:
                    printd(LEVEL_VERBOSE, ".INCBIN %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit binary include metadata.
                    aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case ORIGIN:
                    if (line->keyword_data_expr_1 == NULL)
                    {
                        if (line->keyword_data_string != NULL)
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data);
                        else
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, "");
                    }

                    opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler);
                    printd(LEVEL_VERBOSE, ".ORIGIN 0x%04X", opos);

                    // Emit origin set metadata.
                    aout_emit(aout_create_metadata_origin(opos));

                    break;

                case SEEK:
                    if (line->keyword_data_expr_1 == NULL)
                    {
                        if (line->keyword_data_string != NULL)
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data);
                        else
                            dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, "");
                    }

                    opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler);
                    printd(LEVEL_VERBOSE, ".SEEK 0x%04X", opos);

                    // Emit seek metadata.
                    aout_emit(aout_create_metadata_seek(opos));

                    break;

                case EXPORT:
                    printd(LEVEL_VERBOSE, ".EXPORT %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit export metadata.
                    aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case IMPORT:
                    printd(LEVEL_VERBOSE, ".IMPORT %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit import metadata.
                    aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case IMPORT_OPTIONAL:
                    printd(LEVEL_VERBOSE, ".IMPORT OPTIONAL %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit import metadata.
                    aout_emit(aout_create_metadata_import_optional(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                case JUMP:
                    if (line->keyword_data_string == NULL)
                        printd(LEVEL_VERBOSE, ".JUMP <table>");
                    else
                        printd(LEVEL_VERBOSE, ".JUMP %s", bstr2cstr(line->keyword_data_string, '0'));

                    // Emit jump metadata.
                    if (line->keyword_data_string == NULL)
                        aout_emit(aout_create_metadata_jump(NULL));
                    else
                        aout_emit(aout_create_metadata_jump(bstr2cstr(line->keyword_data_string, '0')));

                    break;

                default:
                    printd(LEVEL_VERBOSE, "?? UNKNOWN KEYWORD\n");
                    dhalt(ERR_UNSUPPORTED_KEYWORD, NULL);
            }

            printd(LEVEL_VERBOSE, "\n");
            break;

        case type_instruction:

            // Check to see if this is DAT.
            if (strcmp(line->instruction->instruction, "DAT") == 0)
            {
                // Handle data.
                printd(LEVEL_VERBOSE, "EMIT DAT");

                // Process parameters as data.
                reverse_parameters(line->instruction->parameters);
                dcurrent = line->instruction->parameters->last;

                while (dcurrent != NULL)
                {
                    // Process parameter normally.
                    dparam = process_parameter(dcurrent);

                    // Output depending on what kind of parameter it was.
                    if (dparam.v_label != NULL) // If this is a label, output something that we need to replace.
                        aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label)))));
                    else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it.
                    {
                        printd(LEVEL_VERBOSE, " \"%s\"", dparam.v_raw->data);

                        for (dchrproc = 0; dchrproc < (uint32_t)blength(dparam.v_raw); dchrproc++)
                            aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc]));
                    }
                    else if (dparam.v_extra_used == true) // Just a single address.
                        aout_emit(aout_create_expr(dparam.v_extra));
                    else // Something that isn't handled by DAT.
                    {
                        printd(LEVEL_VERBOSE, "\n");
                        dhalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL);
                    }

                    dcurrent = dcurrent->prev;
                }
            }
            else
            {
                // Handle instruction.
                insttype = get_instruction_by_name(line->instruction->instruction);

                if (insttype == NULL)
                    dhalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction);

                printd(LEVEL_VERBOSE, "EMIT %s", insttype->name);

                // Check parameter count.
                if (line->instruction->parameters == NULL && strcmp(line->instruction->instruction, "RFI") == 0)
                {
                    // Handle RFI (which can accept no parameters).
                    result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, 0x21 /* 0 literal */));
                    printd(LEVEL_VERBOSE, "\n");
                    break;
                }
                else if (line->instruction->parameters == NULL)
                {
                    // Halt and error.
                    dhalt(ERR_INVALID_PARAMETER_COUNT, NULL);
                }

                // Process parameters normally.
                ppresults = process_parameters(line->instruction->parameters);

                // Force the parameter value to be NXT if it's a label.
                if (ppresults.a_label != NULL) ppresults.a = NXT_LIT;
                if (ppresults.b_label != NULL) ppresults.b = NXT_LIT;
                if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT;
                if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT;

                // Check for relative addressing.
                if ((insttype->opcode == OP_ADD || insttype->opcode == OP_SUB ||
                        insttype->opcode == OP_MUL || insttype->opcode == OP_DIV) && ppresults.a == PC)
                {
                    // Warn about relative addressing portability.
                    dwarn(WARN_RELATIVE_PC_ADDRESSING, NULL);
                }

                // Output the initial opcode.
                if (insttype->opcode != OP_NONBASIC)
                    result = aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b));
                else
                    result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a));

                // If the parameter is a label or requires an extra word, output them.
                if (ppresults.b_label != NULL)
                    aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label)))));
                else if (ppresults.b_extra_used)
                    aout_emit(aout_create_expr(ppresults.b_extra));

                if (ppresults.a_label != NULL)
                    aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label)))));
                else if (ppresults.a_extra_used)
                    aout_emit(aout_create_expr(ppresults.a_extra));

            }

            printd(LEVEL_VERBOSE, "\n");
            break;

        case type_label:
            // Handle label definition.
            list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_LABEL, dbgfmt_create_symbol_label(bfromcstr(line->label->name), DBGFMT_UNDETERMINED)));
            printd(LEVEL_VERBOSE, ":%s\n", line->label->name);
            aout_emit(aout_create_label(line->label->name));
            break;

        default:
            assert(false);
    }

    // If we can associate debugging symbols with this instruction...
    if (result != NULL)
    {
        // While the new symbols list is not empty, copy those symbols
        // into the output and associate.
        while (list_size(&newsyms) > 0)
        {
            newsym = list_extract_at(&newsyms, 0);
            printd(LEVEL_DEBUG, "Debugging custom symbol: %i\n", newsym->length);
            list_append(&result->symbols, newsym);
            list_append(assem_dbg_symbols, newsym);
        }

        // If the line information is provided, output
        // debugging symbols.
        if (line != NULL && line->file != NULL)
        {
            // Output a file / line number debugging symbol here.
            newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->file, line->line, DBGFMT_UNDETERMINED));
            list_append(&result->symbols, newsym);
            list_append(assem_dbg_symbols, newsym);

            printd(LEVEL_DEBUG, "Debugging symbol: %i %s\n", line->line, line->file->data);
        }

        // If the higher-language line information is
        // provided, output debugging symbols.
        if (line != NULL && line->ufile != NULL)
        {
            // Output a file / line number debugging symbol here.
            newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->ufile, line->uline, DBGFMT_UNDETERMINED));
            list_append(&result->symbols, newsym);
            list_append(assem_dbg_symbols, newsym);

            printd(LEVEL_DEBUG, "High-level debugging symbol: %i %s\n", line->uline, line->ufile->data);
        }
    }
}
Beispiel #19
0
struct process_parameter_results process_address(struct ast_node_address* param)
{
    struct process_parameter_results result;
    struct register_mapping* registr;
    bstring btmp = NULL;
    result.v_raw = NULL;

    if (param->value != NULL)
        btmp = expr_representation(param->value);

    if (param->bracketed && param->added)
    {
        // This is of the form [0x1000+I].
        registr = get_register_by_name_next(param->addcmpt);

        if (registr == NULL)
        {
            // Attempt to use a label in square brackets.  Convert this
            // to an expression and then reinvoke ourselves with the
            // evaluated value.
            param->value = expr_new(expr_new_label(bautofree(bfromcstr(param->addcmpt))), EXPR_OP_ADD, param->value);
            param->addcmpt = "";
            param->added = 0;
            param->bracketed = 0;

            bdestroy(btmp);
            return process_address(param);
        }
        else if (registr->value == VALUE_NEXT_UNSUPPORTED)
        {
            // Attempt to use a register in brackets that can't be.
            printd(LEVEL_VERBOSE, "\n");
            dhalt(ERR_NEXTED_REGISTER_UNSUPPORTED, param->addcmpt);
        }

        printd(LEVEL_VERBOSE, "[%s+%s]", btmp->data, registr->name);
        result.v = registr->value;
        result.v_extra = param->value;
        result.v_extra_used = true;
        result.v_label = NULL;
    }
    else
    {
        // This is either the form 0x1000 or [0x1000].
        if (param->bracketed)
        {
            printd(LEVEL_VERBOSE, "[%s]", btmp->data);
            result.v = NXT;
        }
        else
        {
            printd(LEVEL_VERBOSE, "%s", btmp->data);
            result.v = NXT_LIT;
        }

        result.v_extra = param->value;
        result.v_extra_used = true;
        result.v_label = NULL;
    }

    if (btmp != NULL)
        bdestroy(btmp);

    return result;
}
Beispiel #20
0
freed_bstring bautocpy(const_bstring b1)
{
	return bautofree(bstrcpy(b1));
}
Beispiel #21
0
void ppimpl_asm_expr_register(state_t* state)
{
    // Register .IF directive.
    match_t* match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr(".IF "));
    match->handler = if_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register .ELSE directive.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr(".ELSE"));
    match->handler = else_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register .ENDIF directive.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr(".ENDIF"));
    match->handler = endif_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register #IF directive.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr("#IF "));
    match->handler = if_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register #ELSE directive.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr("#ELSE"));
    match->handler = else_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);

    // Register #ENDIF directive.
    match = malloc(sizeof(match_t));
    match->text = bautofree(bfromcstr("#ENDIF"));
    match->handler = endif_handle;
    match->userdata = NULL;
    match->line_start_only = true;
    match->identifier_only = false;
    match->case_insensitive = true;
    ppimpl_register(state, match);
}
Beispiel #22
0
int main(int argc, char* argv[])
{
    int nerrors, w;
    bstring temp = NULL;
    const char* warnprefix = "no-";
    bool expect_failure;
    
    // Define arguments.
    struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
    struct arg_lit* expect_failure_lit = arg_lit0("f", "fail", "Expect failure during preprocessing.");
    struct arg_str* input_lang = arg_str1(NULL, NULL, "<lang>", "The input language.");
    struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input preprocessor file.");
    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, verbose, quiet, expect_failure_lit, input_lang, input_file, end };
    
    // Parse arguments.
    nerrors = arg_parse(argc, argv, argtable);

    if (nerrors != 0 || show_help->count != 0)
    {
        if (nerrors != 0)
            arg_print_errors(stdout, end, "libdcpu-pp test suite");

        printd(LEVEL_DEFAULT, "syntax:\n    dtasm");
        arg_print_syntax(stderr, argtable, "\n");
        printd(LEVEL_DEFAULT, "options:\n");
        arg_print_glossary(stderr, argtable, "    %-25s %s\n");
        if (show_help->count == 2)
        {
            printd(LEVEL_DEFAULT, "defined warnings:\n");
            for (w = 0; w < _WARN_COUNT; w++)
                printd(LEVEL_DEFAULT, "      %s\n", dwarnpolicy[w].name);
        }
        arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
        return 1;
    }
    
    // Set failure expectation variable.
    expect_failure = (expect_failure_lit->count > 0);

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

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

    // Set up error handling.
    if (dsethalt())
    {
        // Handle the error.
        dautohandle();
        printd(LEVEL_ERROR, "libdcpu-pp test suite: error occurred.\n");

        if (temp != NULL)
            pp_cleanup(bautofree(temp));

        arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
        if (expect_failure)
            return 0;
        else
            return 1;
    }
    
    // Perform preprocessing.
    ppfind_add_autopath(bautofree(bfromcstr(input_file->filename[0])));
    temp = pp_do(
        bautofree(bfromcstr(input_lang->sval[0])),
        bautofree(bfromcstr(input_file->filename[0]))
    );
    
    // Perform parsing.
    test_success = true;
    yyin = fopen(temp->data, "r");
    yyout = NULL;
    yyparse();
    fclose(yyin);
    
    // Cleanup.
    pp_cleanup(bautofree(temp));
    
    if (test_success && expect_failure)
        return 1;
    else if (test_success && !expect_failure)
        return 0;
    else if (!test_success && expect_failure)
        return 0;
    else
        return 1;
}
Beispiel #23
0
static void define_handle(state_t* state, match_t* match, bool* reprocess)
{
    // We need to parse this manually because we're interested in getting
    // the first word and then all of the content until a line that doesn't end
    // with "\".
    bstring name = bfromcstr("");
    bstring word = bfromcstr("");
    bstring definition = bfromcstr("");
    bool getting_word = true;
    bool getting_definition = true;
    bool is_macro = false;
    match_t* new_match;
    struct replace_info* info;

    // Get the first word.
    while (getting_word)
    {
        char c = ppimpl_get_input(state);
        bconchar(word, c);
        if (!is_macro && c != '(')
            bconchar(name, c);
        bltrimws(word);

        // Handle termination.
        if (blength(word) > 0 && (c == ' ' || c == '\t') && !is_macro)
        {
            // End of word.
            btrimws(word);
            btrimws(name);
            getting_word = false;
        }
        else if (blength(word) > 0 && c == '(' && !is_macro)
        {
            // Start of macro.
            is_macro = true;
        }
        else if (blength(word) > 0 && c == '(' && is_macro)
        {
            // Second ( in a macro; error.
            dhalt(ERR_PP_MACRO_MALFORMED, ppimpl_get_location(state));
        }
        else if (blength(word) > 0 && c == ')' && is_macro)
        {
            // End of macro name.
            btrimws(word);
            btrimws(name);
            getting_word = false;
        }
        else if (blength(word) == 0 && c == '\n')
            dhalt(ERR_PP_C_DEFINE_PARAMETERS_INCORRECT, ppimpl_get_location(state));
        else if (blength(word) > 0 && c == '\n')
        {
            // End of word.
            btrimws(word);
            btrimws(name);
            getting_word = false;
            getting_definition = false;
            ppimpl_printf(state, "\n");
        }
    }

    // Get the definition.
    while (getting_definition)
    {
        char c = ppimpl_get_input(state);
        bconchar(definition, c);
        bltrimws(definition);
        
        if (c == '\n')
        {
            if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '\\')
            {
                // Remove the new slash.
                bdelete(definition, blength(definition) - 2, 1);
                ppimpl_oprintf(state, "\n");
            }
            else
            {
                btrimws(definition);
                getting_definition = false;
                ppimpl_printf(state, "\n");
            }
        }
        else if (c == '/' || c == '*')
        {
            if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '/')
            {
                // a line or block comment
                ppimpl_iprintf(state, "/%c", c);
                // remove the slashes
                bdelete(definition, blength(definition) - 2, 2);
                btrimws(definition);
                getting_definition = false;
            }
        }
    }
    
    if (blength(definition) == 0 && !is_macro)
        bassigncstr(definition, "1");
        

    // Create the new replacement handler.
    info = malloc(sizeof(struct replace_info));
    info->full = word;
    info->replacement = definition;
    if (biseq(info->full, info->replacement))
    {
        free(info);
        return;
    }
    new_match = malloc(sizeof(match_t));
    new_match->text = bautofree(name);
    if (is_macro)
        new_match->handler = macro_handle;
    else
        new_match->handler = replace_handle;
    new_match->line_start_only = false;
    new_match->identifier_only = true;
    new_match->userdata = info;
    new_match->case_insensitive = false;
    ppimpl_register(state, new_match);
    *reprocess = true;
}
Beispiel #24
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;
}
Beispiel #25
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
}
Beispiel #26
0
///
/// Splits the currently loaded bins into sectioned bins.
///
void bins_sectionize()
{
	struct lconv_entry* entry;
	struct ldbin* bin;
	struct ldbin* target;
	list_t create;
	size_t i;
	int steal, stolen, index, base;
	bstring name;

	list_init(&create);
	list_attributes_seeker(&create, &bin_seeker);

	// Print result information.
	for (i = 0; i < list_size(&ldbins.bins); i++)
	{
		bin = list_get_at(&ldbins.bins, i);
		printd(LEVEL_VERBOSE, "start bin: %s\n", bin->name->data);
		bin->provided != NULL ? printd(LEVEL_VERBOSE, "	 total provided: %u\n", list_size(bin->provided)) : false;
		bin->required != NULL ? printd(LEVEL_VERBOSE, "	 total required: %u\n", list_size(bin->required)) : false;
		bin->adjustment != NULL ? printd(LEVEL_VERBOSE, "  total adjustment: %u\n", list_size(bin->adjustment)) : false;
		bin->section != NULL ? printd(LEVEL_VERBOSE, "	total sections: %u\n", list_size(bin->section)) : false;
		bin->output != NULL ? printd(LEVEL_VERBOSE, "  total outputs: %u\n", list_size(bin->output)) : false;
		printd(LEVEL_VERBOSE, "	 total words: 0x%04X\n", list_size(&bin->words));
		list_iterator_start(&bin->words);
		while (list_iterator_hasnext(&bin->words))
			printd(LEVEL_VERBOSE, "	   0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
		list_iterator_stop(&bin->words);
		printd(LEVEL_VERBOSE, "	 \n");
	}

	// Copy words into appropriate bins.
	list_iterator_start(&ldbins.bins);
	while (list_iterator_hasnext(&ldbins.bins))
	{
		bin = list_iterator_next(&ldbins.bins);

		// Search all of the sections in this bin.
		assert(bin->section != NULL);
		list_iterator_start(bin->section);
		while (list_iterator_hasnext(bin->section))
		{
			entry = list_iterator_next(bin->section);

			// Create target section bin if it doesn't
			// already exist.
			name = bfromcstr("SECTION ");
			bconcat(name, entry->label);
			if (list_seek(&create, name) == NULL)
			{
				target = bin_create(bautofree(name), false);
				target->provided = list_create();
				target->required = list_create();
				target->adjustment = list_create();
				target->output = list_create();
				list_append(&create, target);
			}
			else
				bdestroy(name);
		}
		list_iterator_stop(bin->section);
	}
	list_iterator_stop(&ldbins.bins);

	// For each of the file bins, move the code that they
	// have in sections into the section bins.
	list_iterator_start(&ldbins.bins);
	while (list_iterator_hasnext(&ldbins.bins))
	{
		bin = list_iterator_next(&ldbins.bins);

		// Search all of the sections in this bin.
		stolen = 0;
		assert(bin->section != NULL);
		list_sort(bin->section, 1);
		for (i = 0; i < list_size(bin->section); i++)
		{
			// Work out the target bin.
			name = bfromcstr("SECTION ");
			bconcat(name, ((struct lconv_entry*)list_get_at(bin->section, i))->label);
			target = list_seek(&create, name);
			assert(target != NULL);
			bdestroy(name);

			// Calculate how many bytes to steal from this section.
			if (i == list_size(bin->section) - 1)
			{
				// Steal until end-of-bin.
				steal = list_size(&bin->words) -
					(((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen);
			}
			else
			{
				// Steal up to the next section.
				steal = (((struct lconv_entry*)list_get_at(bin->section, i + 1))->address - stolen) -
					(((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen);
			}

			// Get the index from which to extract.
			index = ((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen;
			base = list_size(&target->words);

			bin_move(target, bin, base, index, steal);
			stolen += steal;
		}
	}
	list_iterator_stop(&ldbins.bins);

	// Append new bins to the bin list and free
	// memory of old list.
	list_iterator_start(&create);
	while (list_iterator_hasnext(&create))
		list_append(&ldbins.bins, list_iterator_next(&create));
	list_iterator_stop(&create);
	list_destroy(&create);

	// Print result information.
	for (i = 0; i < list_size(&ldbins.bins); i++)
	{
		bin = list_get_at(&ldbins.bins, i);
		printd(LEVEL_VERBOSE, "end bin: %s\n", bin->name->data);
		bin->provided != NULL ? printd(LEVEL_VERBOSE, "	 total provided: %u\n", list_size(bin->provided)) : false;
		bin->required != NULL ? printd(LEVEL_VERBOSE, "	 total required: %u\n", list_size(bin->required)) : false;
		bin->adjustment != NULL ? printd(LEVEL_VERBOSE, "  total adjustment: %u\n", list_size(bin->adjustment)) : false;
		bin->section != NULL ? printd(LEVEL_VERBOSE, "	total sections: %u\n", list_size(bin->section)) : false;
		bin->output != NULL ? printd(LEVEL_VERBOSE, "  total outputs: %u\n", list_size(bin->output)) : false;
		printd(LEVEL_VERBOSE, "	 total words: 0x%04X\n", list_size(&bin->words));
		list_iterator_start(&bin->words);
		while (list_iterator_hasnext(&bin->words))
			printd(LEVEL_VERBOSE, "	   0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
		list_iterator_stop(&bin->words);
		printd(LEVEL_VERBOSE, "	 \n");
	}
}
Beispiel #27
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;
}
Beispiel #28
0
int main(int argc, char* argv[])
{
	// Define arguments.
	struct arg_lit* show_help = arg_lit0("h", "help", "Show this help.");
	struct arg_str* type_assembler = arg_str0("t", NULL, "<type>", "The type of assembler to output for.");
	struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file (or - to read from standard input).");
	struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output).");
	struct arg_end* end = arg_end(20);
	void* argtable[] = { output_file, show_help, type_assembler, input_file, end };

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

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

		fprintf(stderr, "syntax:\n    compiler");
		arg_print_syntax(stdout, argtable, "\n");
		fprintf(stderr, "options:\n");
		arg_print_glossary(stdout, argtable, "	  %-25s %s\n");
		return 1;
	}

	fprintf(stderr, "Preprocessing...\n");

	// Run the preprocessor.
	ppfind_add_path(bautofree(bfromcstr(".")));
	ppfind_add_path(bautofree(bfromcstr("include")));
	ppfind_add_autopath(bautofree(bfromcstr(input_file->filename[0])));
	bstring pp_result_name = pp_do(bautofree(bfromcstr(input_file->filename[0])));

	if (pp_result_name == NULL)
	{
		fprintf(stderr, "compiler: invalid result returned from preprocessor.\n");
		pp_cleanup(bautofree(pp_result_name));
		return 1;
	}

	fprintf(stderr, "Parsing C...\n");

	// Parse C.
	yyout = stderr;
	yyin = fopen((const char*)(pp_result_name->data), "r");

	if (yyin == NULL)
	{
		pp_cleanup(bautofree(pp_result_name));
		return 1;
	}

	yyparse();

	if (yyin != stdin)
		fclose(yyin);

	pp_cleanup(bautofree(pp_result_name));

	if (program == NULL)
	{
		std::cerr << "An error occurred while compiling." << std::endl;
		return 1;
	}

	// Assembler type.
	const char* asmtype = "dcpu16toolchain";

	if (type_assembler->count > 0)
		asmtype = type_assembler->sval[0];

	// Spacing.
	std::cerr << std::endl;

	fprintf(stderr, "Generating assembly...\n");

	// Generate assembly using the AST.
	try
	{
		AsmGenerator generator(asmtype);
		AsmBlock* block = program->compile(generator);

		if (strcmp(output_file->filename[0], "-") == 0)
		{
			std::cout << generator.m_Preassembly << std::endl;
			std::cout << *block << std::endl;
			std::cout << generator.m_Postassembly << std::endl;
		}
		else
		{
			std::ofstream output(output_file->filename[0], std::ios::out | std::ios::trunc);
			output << generator.m_Preassembly << std::endl;
			output << *block << std::endl;
			output << generator.m_Postassembly << std::endl;
			output.close();
		}

		delete block;
	}
	catch (CompilerException* ex)
	{
		std::string msg = ex->getMessage();
		std::cerr << "An error occurred while compiling." << std::endl;
		std::cerr << msg << std::endl;
		return 1;
	}

	return 0;
}