// Copyright (C) 2003-2009 Dolphin Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ #include // I hope this doesn't break anything #include #include #include #include #include #include "Common.h" #include "StringUtil.h" #include "DSPCore.h" #include "DSPSymbols.h" #include "disassemble.h" namespace DSPSymbols { DSPSymbolDB g_dsp_symbol_db; std::map addr_to_line; std::map line_to_addr; std::map line_to_symbol; std::vector lines; int line_counter = 0; int Addr2Line(u16 address) // -1 for not found { std::map::iterator iter = addr_to_line.find(address); if (iter != addr_to_line.end()) return iter->second; else return -1; } int Line2Addr(int line) // -1 for not found { std::map::iterator iter = line_to_addr.find(line); if (iter != line_to_addr.end()) return iter->second; else return -1; } const char *GetLineText(int line) { if (line > 0 && line < (int)lines.size()) { return lines[line].c_str(); } else return "----"; } Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr) { XFuncMap::iterator it = functions.find(addr); if (it != functions.end()) return &it->second; else { for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++) { if (addr >= iter->second.address && addr < iter->second.address + iter->second.size) return &iter->second; } } return 0; } // lower case only bool IsHexDigit(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return true; default: return false; } } bool IsAlpha(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } void DisasssembleRange(u16 start, u16 end) { } bool ReadAnnotatedAssembly(const char *filename) { FILE *f = fopen(filename, "r"); if (!f) { ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename); return false; } char line[512]; int last_addr = 0; lines.reserve(3000); // Symbol generation int brace_count = 0; bool symbol_in_progress = false; int symbol_count = 0; Symbol current_symbol; while (fgets(line, 512, f)) { // Scan string for the first 4-digit hex string. size_t len = strlen(line); int first_hex = -1; bool hex_found = false; for (unsigned int i = 0; i < strlen(line); i++) { const char c = line[i]; if (IsHexDigit(c)) { if (first_hex == -1) { first_hex = i; } else { // Remove hex notation if (i == first_hex + 3 && (first_hex == 0 || line[first_hex - 1] != 'x') && (i >= len - 1 || line[i + 1] == ' ')) { hex_found = true; break; } } } else { if (i - first_hex < 3) { first_hex = -1; } if (IsAlpha(c)) break; } } // Scan for function starts if (!memcmp(line, "void", 4)) { char temp[256]; for (int i = 6; i < len; i++) { if (line[i] == '(') { // Yep, got one. memcpy(temp, line + 5, i - 5); temp[i - 5] = 0; // Mark symbol so the next hex sets the address current_symbol.name = temp; current_symbol.address = 0xFFFF; current_symbol.index = symbol_count++; symbol_in_progress = true; // Reset brace count. brace_count = 0; } } } // Scan for braces for (int i = 0; i < (int)len; i++) { if (line[i] == '{') brace_count++; if (line[i] == '}') { brace_count--; if (brace_count == 0 && symbol_in_progress) { // Commit this symbol. current_symbol.size = last_addr - current_symbol.address + 1; g_dsp_symbol_db.AddCompleteSymbol(current_symbol); current_symbol.address = 0xFFFF; symbol_in_progress = false; } } } if (hex_found) { int hex = 0; sscanf(line + first_hex, "%04x", &hex); // Sanity check if (hex > last_addr + 3 || hex < last_addr - 3) { static int errors = 0; ERROR_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line); errors++; if (errors > 10) { fclose(f); return false; } } else { // if (line_counter >= 200 && line_counter <= 220) // NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter); if (symbol_in_progress && current_symbol.address == 0xFFFF) current_symbol.address = hex; line_to_addr[line_counter] = hex; addr_to_line[hex] = line_counter; last_addr = hex; } } lines.push_back(TabsToSpaces(4, line)); line_counter++; } fclose(f); return true; } void AutoDisassembly(u16 start_addr, u16 end_addr) { AssemblerSettings settings; settings.show_pc = true; settings.show_hex = true; DSPDisassembler disasm(settings); u16 addr = start_addr; const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram; while (addr < end_addr) { line_to_addr[line_counter] = addr; addr_to_line[addr] = line_counter; std::string buf; if (!disasm.DisOpcode(ptr, 0, 2, &addr, buf)) { ERROR_LOG(DSPLLE, "disasm failed at %04x", addr); break; } //NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str()); lines.push_back(buf); line_counter++; } } void Clear() { addr_to_line.clear(); line_to_addr.clear(); lines.clear(); line_counter = 0; } } // namespace DSPSymbols