about summary refs log blame commit diff stats
path: root/theme_template
blob: 20393bab4c38aba5a954fd818b68734ba70d337f (plain) (tree)
/span>; // comment if (word_data == ".") continue; // comment token if (word_data == "==") { flush(curr_segment, l); string segment_name; lin >> segment_name; curr_segment = find(out, segment_name); if (curr_segment != NULL) { trace(3, "parse") << "appending to segment '" << segment_name << "'" << end(); } else { trace(3, "parse") << "new segment '" << segment_name << "'" << end(); uint32_t seg_start = 0; lin >> std::hex >> seg_start; sanity_check_program_segment(out, seg_start); out.segments.push_back(segment()); curr_segment = &out.segments.back(); curr_segment->name = segment_name; curr_segment->start = seg_start; if (trace_contains_errors()) continue; trace(3, "parse") << "starts at address 0x" << HEXWORD << curr_segment->start << end(); } break; // skip rest of line } if (word_data[0] == ':') { // todo: line metadata break; } curr.words.push_back(word()); parse_word(word_data, curr.words.back()); trace(99, "parse") << "word: " << to_string(curr.words.back()); } if (!curr.words.empty()) l.push_back(curr); } flush(curr_segment, l); trace(99, "parse") << "done" << end(); } segment* find(program& p, const string& segment_name) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).name == segment_name) return &p.segments.at(i); } return NULL; } void flush(segment* s, vector<line>& lines) { if (lines.empty()) return; if (s == NULL) { raise << "input does not start with a '==' section header\n" << end(); return; } trace(3, "parse") << "flushing segment" << end(); s->lines.insert(s->lines.end(), lines.begin(), lines.end()); lines.clear(); } void parse_word(const string& data, word& out) { out.original = data; istringstream win(data); if (getline(win, out.data, '/')) { string m; while (getline(win, m, '/')) out.metadata.push_back(m); } } void sanity_check_program_segment(const program& p, uint32_t addr) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).start == addr) raise << "can't have multiple segments starting at address 0x" << HEXWORD << addr << '\n' << end(); } } // helper for tests void parse(const string& text_bytes) { program p; istringstream in(text_bytes); parse(in, p); } void test_detect_duplicate_segments() { Hide_errors = true; parse( "== segment1 0xee\n" "ab\n" "== segment2 0xee\n" "cd\n" ); CHECK_TRACE_CONTENTS( "error: can't have multiple segments starting at address 0x000000ee\n" ); } //:: load void load(const program& p) { if (find(p, "code") == NULL) { raise << "no code to run\n" << end(); return; } // Ensure segments are disjoint. set<uint32_t> overlap; for (int i = 0; i < SIZE(p.segments); ++i) { const segment& seg = p.segments.at(i); uint32_t addr = seg.start; if (!already_allocated(addr)) Mem.push_back(vma(seg.start)); trace(99, "load") << "loading segment " << i << " from " << HEXWORD << addr << end(); for (int j = 0; j < SIZE(seg.lines); ++j) { const line& l = seg.lines.at(j); for (int k = 0; k < SIZE(l.words); ++k) { const word& w = l.words.at(k); uint8_t val = hex_byte(w.data); if (trace_contains_errors()) return; assert(overlap.find(addr) == overlap.end()); write_mem_u8(addr, val); overlap.insert(addr); trace(99, "load") << "0x" << HEXWORD << addr << " -> " << HEXBYTE << NUM(read_mem_u8(addr)) << end(); ++addr; } } if (seg.name == "code") { End_of_program = addr; } } } const segment* find(const program& p, const string& segment_name) { for (int i = 0; i < SIZE(p.segments); ++i) { if (p.segments.at(i).name == segment_name) return &p.segments.at(i); } return NULL; } uint8_t hex_byte(const string& s) { if (contains_uppercase(s)) { raise << "uppercase hex not allowed: " << s << '\n' << end(); return 0; } istringstream in(s); int result = 0; in >> std::hex >> result; if (!in || !in.eof()) { raise << "token '" << s << "' is not a hex byte\n" << end(); return '\0'; } if (result > 0xff || result < -0x8f) { raise << "token '" << s << "' is not a hex byte\n" << end(); return '\0'; } return static_cast<uint8_t>(result); } void test_number_too_large() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 cab\n" ); CHECK_TRACE_CONTENTS( "error: token 'cab' is not a hex byte\n" ); } void test_invalid_hex() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 cx\n" ); CHECK_TRACE_CONTENTS( "error: token 'cx' is not a hex byte\n" ); } void test_negative_number() { parse_and_load( "== code 0x1\n" "01 -02\n" ); CHECK_TRACE_COUNT("error", 0); } void test_negative_number_too_small() { Hide_errors = true; parse_and_load( "== code 0x1\n" "01 -12345\n" ); CHECK_TRACE_CONTENTS( "error: token '-12345' is not a hex byte\n" ); } void test_hex_prefix() { parse_and_load( "== code 0x1\n" "0x01 -0x02\n" ); CHECK_TRACE_COUNT("error", 0); } void test_repeated_segment_merges_data() { parse_and_load( "== code 0x1\n" "11 22\n" "== code\n" // again "33 44\n" ); CHECK_TRACE_CONTENTS( "parse: new segment 'code'\n" "parse: appending to segment 'code'\n" // first segment "load: 0x00000001 -> 11\n" "load: 0x00000002 -> 22\n" // second segment "load: 0x00000003 -> 33\n" "load: 0x00000004 -> 44\n" ); } void test_error_on_missing_segment_header() { Hide_errors = true; parse_and_load( "01 02\n" ); CHECK_TRACE_CONTENTS( "error: input does not start with a '==' section header\n" ); } void test_error_on_uppercase_hex() { Hide_errors = true; parse_and_load( "== code\n" "01 Ab\n" ); CHECK_TRACE_CONTENTS( "error: uppercase hex not allowed: Ab\n" ); } //: helper for tests void parse_and_load(const string& text_bytes) { program p; istringstream in(text_bytes); parse(in, p); if (trace_contains_errors()) return; // if any stage raises errors, stop immediately load(p); } //:: run :(before "End Initialize Op Names") put_new(Name, "b8", "copy imm32 to EAX (mov)"); //: our first opcode :(before "End Single-Byte Opcodes") case 0xb8: { // copy imm32 to EAX const int32_t src = next32(); trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to EAX" << end(); Reg[EAX].i = src; break; } :(code) void test_copy_imm32_to_EAX_again() { run( "== code 0x1\n" // code segment // op ModR/M SIB displacement immediate " b8 0a 0b 0c 0d \n" // copy 0x0d0c0b0a to EAX ); CHECK_TRACE_CONTENTS( "run: copy imm32 0x0d0c0b0a to EAX\n" ); } // read a 32-bit int in little-endian order from the instruction stream int32_t next32() { int32_t result = read_mem_i32(EIP); EIP+=4; return result; } //:: helpers string to_string(const word& w) { ostringstream out; out << w.data; for (int i = 0; i < SIZE(w.metadata); ++i) out << " /" << w.metadata.at(i); return out.str(); } bool contains_uppercase(const string& s) { for (int i = 0; i < SIZE(s); ++i) if (isupper(s.at(i))) return true; return false; }