/* * CS 261: Main driver * * Name: Nicholas Tamassia * * This code was developed in compliance with the JMU honor code */ #include "p1-check.h" #include "p2-load.h" #include "p3-disas.h" #include "p4-interp.h" /* * helper function for printing help text */ void usage(char **argv) { printf("Usage: %s mini-elf-file\n", argv[0]); printf(" Options are:\n"); printf(" -h Display usage\n"); printf(" -H Show the Mini-ELF header\n"); printf(" -a Show all with brief memory\n"); printf(" -f Show all with full memory\n"); printf(" -s Show the program headers\n"); printf(" -m Show the memory contents (brief)\n"); printf(" -M Show the memory contents (full)\n"); printf(" -d Disassemble code contents\n"); printf(" -D Disassemble data contents\n"); printf(" -e Execute program\n"); printf(" -E Execute program (trace mode)\n"); } void exit_file_error(FILE *file) { if (file) { fclose(file); } printf("Failed to read file\n"); exit(EXIT_FAILURE); } void execute_y86(y86_t *cpu, byte_t *memory, bool trace) { bool cnd = false; y86_reg_t valA = 0; y86_reg_t valE = 0; printf("Beginning execution at 0x%04lx\n", cpu->pc); /* Dump initial state of cpu */ if (trace) { dump_cpu_state(cpu); } int execution_count = 0; while (cpu->stat == AOK) { y86_inst_t inst = fetch(cpu, memory); if (cpu->stat == ADR || cpu->stat == INS) { if (trace) { printf("\nInvalid instruction at 0x%04lx\n", cpu->pc); } break; } if (trace) { printf("\nExecuting: "); disassemble(&inst); printf("\n"); } valE = decode_execute(cpu, &inst, &cnd, &valA); memory_wb_pc(cpu, &inst, memory, cnd, valA, valE); if (inst.icode == IOTRAP && cpu->stat == HLT) { printf("I/O Error\n"); } if (trace && cpu->stat == AOK) { dump_cpu_state(cpu); } execution_count++; } /* Final state of the cpu */ dump_cpu_state(cpu); printf("Total execution count: %d\n", execution_count); if (trace) { printf("\n"); dump_memory(memory, 0, MEMSIZE); } } int main(int argc, char **argv) { int c; bool show_elf_header = false; bool show_program_header = false; bool show_memory_brief = false; bool show_memory_full = false; bool show_code = false; bool show_data = false; bool execute_default = false; bool execute_trace = false; while ((c = getopt(argc, argv, "hHafsmMdDeE")) != -1) { switch (c) { case 'h': usage(argv); return EXIT_SUCCESS; case 'H': show_elf_header = true; break; case 'a': show_elf_header = true; show_program_header = true; show_memory_brief = true; break; case 'f': show_elf_header = true; show_program_header = true; show_memory_full = true; break; case 's': show_program_header = true; break; case 'm': show_memory_brief = true; break; case 'M': show_memory_full = true; break; case 'd': show_code = true; break; case 'D': show_data = true; break; case 'e': execute_default = true; break; case 'E': execute_trace = true; break; default: usage(argv); return EXIT_FAILURE; } } /* File path was not the last argument */ bool invalid_arguments = optind != argc - 1; /* Attempted to ask for brief and full memory at same time */ bool memory_flag_conflict = show_memory_brief && show_memory_full; /* Attempted to execute program in both default and trace mode */ bool execute_flag_conflict = execute_default && execute_trace; if (invalid_arguments || memory_flag_conflict || execute_flag_conflict) { usage(argv); return EXIT_FAILURE; } elf_hdr_t header = {0}; FILE *header_file = fopen(argv[optind], "r"); /* Read contents of header_file into header */ if (!read_header(header_file, &header)) { exit_file_error(header_file); } if (show_elf_header) { dump_header(&header); } elf_phdr_t phdrs[header.e_num_phdr]; memset(phdrs, 0, sizeof(phdrs)); /* Read program headers into phdrs array */ for (int i = 0; i < header.e_num_phdr; i++) { uint16_t offset = header.e_phdr_start + i * sizeof(elf_phdr_t); if (!read_phdr(header_file, offset, &phdrs[i])) { exit_file_error(header_file); } } if (show_program_header) { dump_phdrs(header.e_num_phdr, phdrs); } byte_t memory[MEMSIZE]; memset(memory, 0, MEMSIZE); /* Read memory segments into memory array */ for (int i = 0; i < header.e_num_phdr; i++) { if (!load_segment(header_file, memory, &phdrs[i])) { exit_file_error(header_file); } } fclose(header_file); if (show_memory_brief) { for (int i = 0; i < header.e_num_phdr; i++) { uint32_t start = phdrs[i].p_vaddr; uint32_t end = start + phdrs[i].p_size; dump_memory(memory, start, end); } } else if (show_memory_full) { dump_memory(memory, 0, MEMSIZE); } if (show_code) { printf("Disassembly of executable contents:\n"); for (int i = 0; i < header.e_num_phdr; i++) { if (phdrs[i].p_type == CODE) { disassemble_code(memory, &phdrs[i], &header); } } } if (show_data) { printf("Disassembly of data contents:\n"); for (int i = 0; i < header.e_num_phdr; i++) { if (phdrs[i].p_type == DATA && phdrs[i].p_flags == 4) { disassemble_rodata(memory, &phdrs[i]); } else if (phdrs[i].p_type == DATA) { disassemble_data(memory, &phdrs[i]); } } } if (execute_default || execute_trace) { y86_t cpu = {0}; cpu.stat = AOK; cpu.pc = header.e_entry; execute_y86(&cpu, memory, execute_trace); } return EXIT_SUCCESS; }