From: slack Date: Sun, 17 Aug 2008 01:30:43 +0000 (+0200) Subject: disassembler works now :D X-Git-Tag: v0.1~12 X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=fd693dae55bf0104baccb143546ebf516fbadef8;p=wenboi.git disassembler works now :D --- diff --git a/wendi/CodeBlock.cc b/wendi/CodeBlock.cc index 06f4698..091417d 100644 --- a/wendi/CodeBlock.cc +++ b/wendi/CodeBlock.cc @@ -4,17 +4,21 @@ #include CodeBlock::CodeBlock(address start): //< creates an empty CodeBlock + type(BLOCK), start(start), end(start), disassembly(), - xrefs() + xrefs(), + name() {} CodeBlock::CodeBlock(CodeBlock &block, address addr): //< removes [addr,end[ from the block creating a new one + type(BLOCK), start(addr), end(block.end), disassembly(), - xrefs() + xrefs(), + name() { using std::bind2nd; using __gnu_cxx::select1st; @@ -30,6 +34,15 @@ CodeBlock::CodeBlock(CodeBlock &block, address addr): //< removes [addr,end[ fro disassembly.splice(disassembly.end(), block.disassembly, first, last); } +CodeBlock::CodeBlock(CodeBlockType type, address start, address end): + type(type), + start(start), + end(end), + disassembly(), + xrefs(), + name() +{ +} void CodeBlock::add_instruction(std::string ins, int nbytes) // appends an instruction to the end of the block { diff --git a/wendi/CodeBlock.h b/wendi/CodeBlock.h index acffda5..4d4b8df 100644 --- a/wendi/CodeBlock.h +++ b/wendi/CodeBlock.h @@ -13,6 +13,20 @@ typedef u16 address; class CodeBlock { public: + enum CodeBlockType + { + BLOCK = 0x000, + FUNCTION = 0x001, + VBLANK_HANDLER = 0x002, + LCD_STAT_HANDLER = 0x004, + TIMER_HANDLER = 0x008, + SERIAL_HANDLER = 0x010, + JOYPAD_HANDLER = 0x020, + ENTRYPOINT = 0x040, + JUMP_TABLE = 0x080, + JUMP_TABLE_DEST = 0x100, + }; + typedef std::pair DisassemblyItem; typedef std::pair XrefsItem; typedef std::list DisassemblyList; @@ -23,13 +37,17 @@ class CodeBlock typedef XrefsVector::iterator XrefsIterator; typedef XrefsVector::const_iterator XrefsConstIterator; + int type; + address start, end; // block is [start, end[ DisassemblyList disassembly; XrefsVector xrefs; + std::string name; CodeBlock(address start); //< creates an empty CodeBlock CodeBlock(CodeBlock &block, address addr); //< removes [addr,end[ from the block creating a new one + CodeBlock(CodeBlockType type, address start, address end); // Creates a "raw" block int length() { return end-start; } void add_instruction(std::string ins, int nbytes); // appends an instruction to the end of the block diff --git a/wendi/Instruction.h b/wendi/Instruction.h index 41aa0aa..8698f42 100644 --- a/wendi/Instruction.h +++ b/wendi/Instruction.h @@ -9,19 +9,21 @@ struct Instruction { UNCONDITIONAL_JUMP=0, CONDITIONAL_JUMP, + UNCONDITIONAL_RET, + CONDITIONAL_RET, CALL, - RET, RESET, ALU, LOAD, - OTHER + OTHER, + JUMP_TABLE_JUMP, }; enum InstructionSubType { JP, JR, - } + }; enum Register { A=0,B,C,D,E,H,L,AF,BC,DE,HL,SP,PC }; diff --git a/wendi/disasm.cc b/wendi/disasm.cc index ddb87d0..11f201f 100644 --- a/wendi/disasm.cc +++ b/wendi/disasm.cc @@ -503,14 +503,14 @@ Instruction disassemble_opcode(GameBoy &gb, u16 addr) dis(0xFF, "RST 0x38", Instruction::RESET) // Returns - dis(0xC9, "RET", Instruction::RET) + dis(0xC9, "RET", Instruction::UNCONDITIONAL_RET) // RET cc - dis(0xC0, "RET NZ", Instruction::RET) - dis(0xC8, "RET Z", Instruction::RET) - dis(0xD0, "RET NC", Instruction::RET) - dis(0xD8, "RET C", Instruction::RET) + dis(0xC0, "RET NZ", Instruction::CONDITIONAL_RET) + dis(0xC8, "RET Z", Instruction::CONDITIONAL_RET) + dis(0xD0, "RET NC", Instruction::CONDITIONAL_RET) + dis(0xD8, "RET C", Instruction::CONDITIONAL_RET) - dis(0xD9, "RETI", Instruction::RET) + dis(0xD9, "RETI", Instruction::UNCONDITIONAL_RET) default: std::ostringstream errmsg; diff --git a/wendi/wendi.cc b/wendi/wendi.cc index e7ea524..421f27e 100644 --- a/wendi/wendi.cc +++ b/wendi/wendi.cc @@ -8,9 +8,12 @@ #include #include #include +#include +#include #include #include #include +#include //#include using std::vector; @@ -24,72 +27,147 @@ typedef u16 address; list blocks; list pending; -void show_block(const CodeBlock& b) + +void classify_block(CodeBlock &b) { - bool is_CALLed = false; - bool is_VBLANK_interrupt_handler = false; - bool is_LCD_STAT_interrupt_handler = false; - bool is_TIMER_interrupt_handler = false; - bool is_SERIAL_interrupt_handler = false; - bool is_JOYPAD_interrupt_handler = false; - std::ostringstream headerstr; - - // Create header, check for CALL xrefs - headerstr << "block_0x" << std::hex << b.start << ":"; - if (!b.xrefs.empty()) - headerstr << "\t;xrefs "; + std::ostringstream block_name; + if (b.start == 0x100) + b.type |= CodeBlock::ENTRYPOINT; + + // check for CALL xrefs; build xrefs list string + std::sort(b.xrefs.begin(), b.xrefs.end()); for(CodeBlock::XrefsConstIterator i=b.xrefs.begin(); i!=b.xrefs.end(); i++) { - headerstr << std::hex << "0x" << i->first << ","; if (i->second == Instruction::CALL) - is_CALLed = true; + b.type |= CodeBlock::FUNCTION; + if (i->second == Instruction::JUMP_TABLE_JUMP) + b.type |= CodeBlock::JUMP_TABLE_DEST; if (i->first == 0x40) - is_VBLANK_interrupt_handler = true; + b.type |= CodeBlock::VBLANK_HANDLER; if (i->first == 0x48) - is_LCD_STAT_interrupt_handler = true; + b.type |= CodeBlock::LCD_STAT_HANDLER; if (i->first == 0x50) - is_TIMER_interrupt_handler = true; + b.type |= CodeBlock::TIMER_HANDLER; if (i->first == 0x58) - is_SERIAL_interrupt_handler = true; + b.type |= CodeBlock::SERIAL_HANDLER; if (i->first == 0x60) - is_JOYPAD_interrupt_handler = true; + b.type |= CodeBlock::JOYPAD_HANDLER; + } + + if (b.type & CodeBlock::ENTRYPOINT) + block_name << "entrypoint"; + else if (b.start == 0x40) + block_name << "vblank_interrupt"; + else if (b.start == 0x48) + block_name << "lcd_stat_interrupt"; + else if (b.start == 0x50) + block_name << "timer_interrupt"; + else if (b.start == 0x58) + block_name << "serial_interrupt"; + else if (b.start == 0x60) + block_name << "joypad_interrupt"; + else + { + if (b.type & + (CodeBlock::VBLANK_HANDLER | + CodeBlock::LCD_STAT_HANDLER | + CodeBlock::TIMER_HANDLER | + CodeBlock::SERIAL_HANDLER | + CodeBlock::JOYPAD_HANDLER)) + { + block_name << "handler"; + } + else if (b.type & CodeBlock::FUNCTION) + { + block_name << "function"; + } + else if (b.type & CodeBlock::JUMP_TABLE_DEST) + { + block_name << "jump"; + } + else + { + block_name << "block"; + } + + block_name << "_0x" << std::hex << std::setw(4) << std::setfill('0') << b.start; + } + + b.name = block_name.str(); +} + + +void show_jump_table_block(GameBoy &gb, const CodeBlock &b) +{ + int n = (b.end - b.start)/2; + + std::cout << ";-- JUMP TABLE ------------------------" << std::endl; + for (int i=0; ifirst << ","; } - headerstr << std::endl; + xrefsstr << std::endl; // Print header to stdout - if (is_CALLed) - std::cout << std::endl << "-- FUNCTION --------------------------" << std::endl; - if (is_VBLANK_interrupt_handler) - std::cout << std::endl << "-- VBLANK INTERRUPT HANDLER ----------" << std::endl; - if (is_LCD_STAT_interrupt_handler) - std::cout << std::endl << "-- LCD_STAT INTERRUPT HANDLER --------" << std::endl; - if (is_TIMER_interrupt_handler) - std::cout << std::endl << "-- TIMER INTERRUPT HANDLER -----------" << std::endl; - if (is_SERIAL_interrupt_handler) - std::cout << std::endl << "-- SERIAL INTERRUPT HANDLER ----------" << std::endl; - if (is_JOYPAD_interrupt_handler) - std::cout << std::endl << "-- JOYPAD INTERRUPT HANDLER ----------" << std::endl; + if (b.type & CodeBlock::FUNCTION) + std::cout << std::endl << ";-- FUNCTION --------------------------" << std::endl; + if (b.type & CodeBlock::VBLANK_HANDLER) + std::cout << std::endl << ";-- VBLANK INTERRUPT HANDLER ----------" << std::endl; + if (b.type & CodeBlock::LCD_STAT_HANDLER) + std::cout << std::endl << ";-- LCD_STAT INTERRUPT HANDLER --------" << std::endl; + if (b.type & CodeBlock::TIMER_HANDLER) + std::cout << std::endl << ";-- TIMER INTERRUPT HANDLER -----------" << std::endl; + if (b.type & CodeBlock::SERIAL_HANDLER) + std::cout << std::endl << ";-- SERIAL INTERRUPT HANDLER ----------" << std::endl; + if (b.type & CodeBlock::JOYPAD_HANDLER) + std::cout << std::endl << ";-- JOYPAD INTERRUPT HANDLER ----------" << std::endl; - if (b.start == 0x100) - std::cout << std::endl << "-- ENTRYPOINT -----------------" << std::endl; + if (b.type & CodeBlock::ENTRYPOINT) + std::cout << std::endl << ";-- ENTRYPOINT ------------------------" << std::endl; + + std::cout << b.name << ":"; - std::cout << headerstr.str(); + std::cout << xrefsstr.str(); // Print disassembly for(CodeBlock::DisassemblyConstIterator i=b.disassembly.begin(); i!=b.disassembly.end(); i++) - std::cout << std::hex << "0x" << i->first << "\t" << i->second << std::endl; + { + std::cout << std::hex << "\t0x" << + std::setw(4) << std::setfill('0') << i->first << + "\t" << i->second << std::endl; + } } bool is_block_end(const Instruction &ins) { if (ins.type == Instruction::UNCONDITIONAL_JUMP || - ins.type == Instruction::RET || + ins.type == Instruction::UNCONDITIONAL_RET || ins.type == Instruction::RESET) return true; @@ -155,6 +233,65 @@ list::iterator find_block(list &l, address addr) return i; } +void hexdump(GameBoy &gb, address start, address end) +{ + if (end > start) + { + std::cout << std::endl << ";-- HEXDUMP ---------------------------"; + address i=start - (start%0x10); + if (i &v) +{ + //std::for_each(tmp.begin(), tmp.end(), show_block); + + const address MAX_ADDRESS = 0xFFFF; + address last = 0; + for (vector::iterator i=v.begin(); + i != v.end(); i++) + { + hexdump(gb, last, i->start); + switch (i->type) + { + case CodeBlock::JUMP_TABLE: + show_jump_table_block(gb, *i); + break; + default: + show_disassembly_block(*i); + } + last = i->end; + } + + hexdump(gb, v.back().end, MAX_ADDRESS); +} + int main(int argc, char **argv) { logger.set_log_level(Logger::TRACE); @@ -169,6 +306,47 @@ int main(int argc, char **argv) pending.push_back(CodeBlock(0x58)); pending.push_back(CodeBlock(0x60)); + if (argc > 2) + { + std::ifstream config(argv[2]); + while (!config.eof()) + { + std::string cmd; + config >> cmd; + if (cmd == "block") + { + address a; + config >> std::hex >> a; + pending.push_back(CodeBlock(a)); + } + else if (cmd == "jump_table") + { + address start, end; + config >> std::hex >> start >> end; + logger.trace("jump table block at 0x",std::hex, start); + blocks.push_back(CodeBlock(CodeBlock::JUMP_TABLE, start, end)); + // add all destinations to pending + int n = (end - start)/2; + for (int i=0; i::iterator i = find_block(pending, dst); + if (i == pending.end()) + { + logger.trace("jump table dst block at 0x",std::hex, dst); + pending.push_back(CodeBlock(dst)); + pending.back().add_xref(src, Instruction::JUMP_TABLE_JUMP); + } + else + { + i->add_xref(src, Instruction::JUMP_TABLE_JUMP); + } + } + } + } + } + while(!pending.empty()) { // Disassemble a block @@ -237,12 +415,18 @@ int main(int argc, char **argv) } } - if (is_block_end(ins)) + addr += ins.length; + + // If new addr is in another block, this block is over + if (find_block(blocks, addr) != blocks.end() || + find_block(pending, addr) != pending.end() || + is_block_end(ins)) { block_end=true; } + + - addr += ins.length; } blocks.push_back(block); @@ -252,7 +436,9 @@ int main(int argc, char **argv) for (list::iterator i = blocks.begin(); i != blocks.end(); i++) tmp.push_back(*i); std::sort(tmp.begin(), tmp.end()); - std::for_each(tmp.begin(), tmp.end(), show_block); - + std::for_each(tmp.begin(), tmp.end(), classify_block); + + show_disassembly(gb, tmp); + return 0; }