From f54d9e33c256560e0c06041cc2c480d6ada32c6e Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Mon, 15 Dec 2014 08:47:36 +1030 Subject: [PATCH 1/8] Fix many bugs with the Symbols menu (when run with -d argument). The Symbols menu is now fully useable. --- Source/Core/Core/Boot/Boot.cpp | 6 +- Source/Core/Core/Boot/Boot.h | 5 +- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 15 ++- Source/Core/Core/PowerPC/SignatureDB.cpp | 5 +- Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 4 + .../Debugger/CodeWindowFunctions.cpp | 127 ++++++++++++++++-- Source/Core/DolphinWX/Globals.h | 6 +- Tools/ReadDolphinMap.idc | 62 +++++++++ 8 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 Tools/ReadDolphinMap.idc diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 349ea0893c..fa297d70e6 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -67,7 +67,8 @@ void CBoot::UpdateDebugger_MapLoaded() } bool CBoot::FindMapFile(std::string* existing_map_file, - std::string* writable_map_file) + std::string* writable_map_file, + std::string* title_id) { std::string title_id_str; size_t name_begin_index; @@ -109,6 +110,9 @@ bool CBoot::FindMapFile(std::string* existing_map_file, if (writable_map_file) *writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map"; + if (title_id) + *title_id = title_id_str; + bool found = false; static const std::string maps_directories[] = { File::GetUserPath(D_MAPS_IDX), diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 973e94cbcd..c97099d24f 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -36,9 +36,12 @@ public: // If writable_map_file is not nullptr, it is set to the path to where a map // file should be saved. // + // If title_id is not nullptr, it is set to the title id + // // Returns true if a map file exists, false if none could be found. static bool FindMapFile(std::string* existing_map_file, - std::string* writable_map_file); + std::string* writable_map_file, + std::string* title_id = nullptr); private: static void RunFunction(u32 _iAddr); diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index b88d7f1362..9afa79178a 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -63,7 +63,7 @@ void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& nam // already got it, let's just update name, checksum & size to be sure. Symbol *tempfunc = &iter->second; tempfunc->name = name; - tempfunc->hash = SignatureDB::ComputeCodeChecksum(startAddr, startAddr + size); + tempfunc->hash = SignatureDB::ComputeCodeChecksum(startAddr, startAddr + size - 4); tempfunc->type = type; tempfunc->size = size; } @@ -235,7 +235,16 @@ bool PPCSymbolDB::LoadMap(const std::string& filename) u32 address, vaddress, size, unknown; char name[512]; - sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); + // some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")" + // instead of a space followed by a number followed by a space followed by a name + if (strlen(line) > 27 && line[27] != ' ' && strstr(line, "(entry of ")) + { + sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); + } + else + { + sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); + } const char *namepos = strstr(line, name); if (namepos != nullptr) //would be odd if not :P @@ -250,7 +259,7 @@ bool PPCSymbolDB::LoadMap(const std::string& filename) } // Check if this is a valid entry. - if (strcmp(name, ".text") != 0 || strcmp(name, ".init") != 0 || strlen(name) > 0) + if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) { AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION } diff --git a/Source/Core/Core/PowerPC/SignatureDB.cpp b/Source/Core/Core/PowerPC/SignatureDB.cpp index 7496361681..d20a041e58 100644 --- a/Source/Core/Core/PowerPC/SignatureDB.cpp +++ b/Source/Core/Core/PowerPC/SignatureDB.cpp @@ -77,7 +77,7 @@ bool SignatureDB::Save(const std::string& filename) //Adds a known function to the hash database u32 SignatureDB::Add(u32 startAddr, u32 size, const std::string& name) { - u32 hash = ComputeCodeChecksum(startAddr, startAddr + size); + u32 hash = ComputeCodeChecksum(startAddr, startAddr + size - 4); DBFunc temp_dbfunc; temp_dbfunc.size = size; @@ -134,7 +134,8 @@ void SignatureDB::Initialize(PPCSymbolDB *symbol_db, const std::string& prefix) { for (const auto& symbol : symbol_db->Symbols()) { - if ((symbol.second.name.substr(0, prefix.size()) == prefix) || prefix.empty()) + if ((prefix.empty() && (!symbol.second.name.empty()) && symbol.second.name.substr(0, 3) != "zz_" && symbol.second.name.substr(0, 1) != ".") || + ((!prefix.empty()) && symbol.second.name.substr(0, prefix.size()) == prefix)) { DBFunc temp_dbfunc; temp_dbfunc.name = symbol.second.name; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index debf26345d..fb69650567 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -752,8 +752,12 @@ void CCodeWindow::UpdateButtonStates() GetMenuBar()->Enable(IDM_SCANFUNCTIONS, Initialized); GetMenuBar()->Enable(IDM_LOADMAPFILE, Initialized); GetMenuBar()->Enable(IDM_SAVEMAPFILE, Initialized); + GetMenuBar()->Enable(IDM_LOADMAPFILEAS, Initialized); + GetMenuBar()->Enable(IDM_SAVEMAPFILEAS, Initialized); GetMenuBar()->Enable(IDM_SAVEMAPFILEWITHCODES, Initialized); GetMenuBar()->Enable(IDM_CREATESIGNATUREFILE, Initialized); + GetMenuBar()->Enable(IDM_APPENDSIGNATUREFILE, Initialized); + GetMenuBar()->Enable(IDM_COMBINESIGNATUREFILES, Initialized); GetMenuBar()->Enable(IDM_RENAME_SYMBOLS, Initialized); GetMenuBar()->Enable(IDM_USESIGNATUREFILE, Initialized); GetMenuBar()->Enable(IDM_PATCHHLEFUNCTIONS, Initialized); diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index 099d184bee..cba74774da 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -146,11 +146,19 @@ void CCodeWindow::Save() void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) { wxMenu *pSymbolsMenu = new wxMenu; - pSymbolsMenu->Append(IDM_CLEARSYMBOLS, _("&Clear symbols")); - pSymbolsMenu->Append(IDM_SCANFUNCTIONS, _("&Generate symbol map")); + pSymbolsMenu->Append(IDM_CLEARSYMBOLS, _("&Clear symbols"), + _("Remove names from all functions and variables.")); + pSymbolsMenu->Append(IDM_SCANFUNCTIONS, _("&Generate symbol map"), + _("Recognise standard functions from sys\\totaldb.dsy, and use generic zz_ names for other functions.")); pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_LOADMAPFILE, _("&Load symbol map")); - pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map")); + pSymbolsMenu->Append(IDM_LOADMAPFILE, _("&Load symbol map"), + _("Try to load this game's function names automatically - but doesn't check .map files stored on the disc image yet.")); + pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map"), + _("Save the function names for each address to a .map file in your user settings map folder, named after the title id.")); + pSymbolsMenu->Append(IDM_LOADMAPFILEAS, _("Choose symbol map file to load..."), + _("Load any .map file containing the function names and addresses for this game.")); + pSymbolsMenu->Append(IDM_SAVEMAPFILEAS, _("Save symbol map &as..."), + _("Save the function names and addresses for this game as a .map file. If you want to open it in IDA pro, use the .idc script.")); pSymbolsMenu->AppendSeparator(); pSymbolsMenu->Append(IDM_SAVEMAPFILEWITHCODES, _("Save code"), _("Save the entire disassembled code. This may take a several seconds" @@ -161,8 +169,14 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) ); pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_CREATESIGNATUREFILE, _("&Create signature file...")); - pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _("&Use signature file...")); + pSymbolsMenu->Append(IDM_CREATESIGNATUREFILE, _("&Create signature file..."), + _("Create a .dsy file that can be used to recognise these same functions in other games.")); + pSymbolsMenu->Append(IDM_APPENDSIGNATUREFILE, _("Append to &existing signature file..."), + _("Add any named functions missing from a .dsy file, so it can also recognise these additional functions in other games.")); + pSymbolsMenu->Append(IDM_COMBINESIGNATUREFILES, _("Combine &2 signature files..."), + _("Make a new .dsy file which can recognise more functions, by combining two existing files. The first input file has priority.")); + pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _("&Use signature file..."), + _("Must use Generate symbol map first! Recognise names of any standard library functions used in multiple games, by loading them from a .dsy file.")); pSymbolsMenu->AppendSeparator(); pSymbolsMenu->Append(IDM_PATCHHLEFUNCTIONS, _("&Patch HLE functions")); pSymbolsMenu->Append(IDM_RENAME_SYMBOLS, _("&Rename symbols from file...")); @@ -222,9 +236,10 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) if (!Core::IsRunning()) return; - std::string existing_map_file, writable_map_file; + std::string existing_map_file, writable_map_file, title_id_str; bool map_exists = CBoot::FindMapFile(&existing_map_file, - &writable_map_file); + &writable_map_file, + &title_id_str); switch (event.GetId()) { case IDM_CLEARSYMBOLS: @@ -240,6 +255,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) { db.Apply(&g_symbolDB); Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB); + db.List(); } else { @@ -268,9 +284,38 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) HLE::PatchFunctions(); NotifyMapLoaded(); break; + case IDM_LOADMAPFILEAS: + { + const wxString path = wxFileSelector( + _("Load map file"), File::GetUserPath(D_MAPS_IDX), + title_id_str + ".map", ".map", + "Dolphin Map File (*.map)|*.map|All files (*.*)|*.*", + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + + if (!path.IsEmpty()) + { + g_symbolDB.LoadMap(WxStrToStr(path)); + Parent->StatusBarMessage("Loaded symbols from '%s'", path.c_str()); + } + HLE::PatchFunctions(); + NotifyMapLoaded(); + } + break; case IDM_SAVEMAPFILE: g_symbolDB.SaveMap(writable_map_file); break; + case IDM_SAVEMAPFILEAS: + { + const wxString path = wxFileSelector( + _("Save map file as"), File::GetUserPath(D_MAPS_IDX), + title_id_str + ".map", ".map", + "Dolphin Map File (*.map)|*.map|All files (*.*)|*.*", + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); + + if (!path.IsEmpty()) + g_symbolDB.SaveMap(WxStrToStr(path)); + } + break; case IDM_SAVEMAPFILEWITHCODES: g_symbolDB.SaveMap(writable_map_file, true); break; @@ -323,14 +368,43 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) std::string prefix(WxStrToStr(input_prefix.GetValue())); wxString path = wxFileSelector( - _("Save signature as"), wxEmptyString, wxEmptyString, wxEmptyString, - "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_SAVE, + _("Save signature as"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); if (!path.IsEmpty()) { SignatureDB db; db.Initialize(&g_symbolDB, prefix); db.Save(WxStrToStr(path)); + db.List(); + } + } + } + break; + case IDM_APPENDSIGNATUREFILE: + { + wxTextEntryDialog input_prefix( + this, + _("Only export symbols with prefix:\n(Blank for all symbols)"), + wxGetTextFromUserPromptStr, + wxEmptyString); + + if (input_prefix.ShowModal() == wxID_OK) + { + std::string prefix(WxStrToStr(input_prefix.GetValue())); + + wxString path = wxFileSelector( + _("Append signature to"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_SAVE, + this); + if (!path.IsEmpty()) + { + SignatureDB db; + db.Initialize(&g_symbolDB, prefix); + db.List(); + db.Load(WxStrToStr(path)); + db.Save(WxStrToStr(path)); + db.List(); } } } @@ -338,7 +412,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) case IDM_USESIGNATUREFILE: { wxString path = wxFileSelector( - _("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Apply signature file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); if (!path.IsEmpty()) @@ -346,9 +420,38 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) SignatureDB db; db.Load(WxStrToStr(path)); db.Apply(&g_symbolDB); + db.List(); + NotifyMapLoaded(); + } + } + break; + case IDM_COMBINESIGNATUREFILES: + { + wxString path1 = wxFileSelector( + _("Choose priority input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_OPEN | wxFD_FILE_MUST_EXIST, + this); + if (!path1.IsEmpty()) + { + SignatureDB db; + wxString path2 = wxFileSelector( + _("Choose secondary input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_OPEN | wxFD_FILE_MUST_EXIST, + this); + if (!path2.IsEmpty()) + { + db.Load(WxStrToStr(path2)); + db.Load(WxStrToStr(path1)); + + path2 = wxFileSelector( + _("Save combined output file as"), File::GetSysDirectory(), wxEmptyString, ".dsy", + "Dolphin Signature File (*.dsy)|*.dsy;", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, + this); + db.Save(WxStrToStr(path2)); + db.List(); + } } } - NotifyMapLoaded(); break; case IDM_PATCHHLEFUNCTIONS: HLE::PatchFunctions(); diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 42ae34b87a..3df4f95996 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -214,9 +214,11 @@ enum // Symbols IDM_CLEARSYMBOLS, IDM_SCANFUNCTIONS, - IDM_LOADMAPFILE, - IDM_SAVEMAPFILE, IDM_SAVEMAPFILEWITHCODES, + IDM_LOADMAPFILE, IDM_LOADMAPFILEAS, + IDM_SAVEMAPFILE, IDM_SAVEMAPFILEWITHCODES, IDM_SAVEMAPFILEAS, IDM_CREATESIGNATUREFILE, + IDM_APPENDSIGNATUREFILE, + IDM_COMBINESIGNATUREFILES, IDM_RENAME_SYMBOLS, IDM_USESIGNATUREFILE, IDM_PATCHHLEFUNCTIONS, diff --git a/Tools/ReadDolphinMap.idc b/Tools/ReadDolphinMap.idc new file mode 100644 index 0000000000..a092b4c35d --- /dev/null +++ b/Tools/ReadDolphinMap.idc @@ -0,0 +1,62 @@ +/* ReadDolphinMap.idc + + Loads .map files generated by dolphin. + Carl Kenner, 2012 +*/ + +#include + +static main(void) +{ + auto fh; + auto fname; + auto pusha, popa; + auto start, end; + auto success; + auto count; + auto line; + auto ea; // column 1 + auto name; // column 30 + auto p; + auto code; + + fname = AskFile(0,"*.map","Load a .map file from Dolphin emulator..."); + + fh = fopen(fname, "r"); + if (fh == 0) { + Message("Can't open %s\n", fname); + return; + } + + Message("Loading %s dolphin map file:\n", fname); + + for (count = 0; 1; count++) { + line = readstr(fh); + if (line == -1) + break; + if (strlen(line)>30 && line[0]!=" ") { + ea = xtol(substr(line,0,8)); + name = substr(line,29,strlen(line)-1); + if (substr(name,0,3)!="zz_") { + if (!MakeNameEx(ea,name,SN_NOCHECK | SN_PUBLIC | SN_NON_AUTO |SN_NOWARN)) { + MakeNameEx(ea,name+"_2",SN_NOCHECK | SN_PUBLIC | SN_NON_AUTO ); + } + Message("ea='%x', name='%s'\n", ea, name); + } else { + MakeNameEx(ea,name,SN_NOCHECK | SN_PUBLIC | SN_AUTO | SN_WEAK | SN_NOWARN); + } + } else if (strlen(line)>30) { + ea = xtol(substr(line,18,18+8)); + p = strstr(line, " \t"); + if (p>=30 && ea!=0) { + name = substr(line,30,p); + code = substr(line,p+2,strlen(line)); + SetFunctionCmt(ea, code, 0); + if (!MakeNameEx(ea,name,SN_NOCHECK | SN_PUBLIC | SN_NON_AUTO |SN_NOWARN)) { + MakeNameEx(ea,name+"_2",SN_NOCHECK | SN_PUBLIC | SN_NON_AUTO ); + } + } + } + } + Message("Dolphin map file done.\n"); +} From e246aaf419c34e23e6c37013e0b7ed7dbf11ba21 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Mon, 15 Dec 2014 10:13:45 +1030 Subject: [PATCH 2/8] Add "Load bad map file" option for map files on disc that don't quite match. Currently it is very simple and naive, but filters out most of the bad matches. --- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 95 +++++++++++++++++++ Source/Core/Core/PowerPC/PPCSymbolDB.h | 1 + Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 1 + .../Debugger/CodeWindowFunctions.cpp | 20 ++++ Source/Core/DolphinWX/DolphinWX.vcxproj.user | 8 +- Source/Core/DolphinWX/Globals.h | 2 +- 6 files changed, 125 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 9afa79178a..1d6f5076ce 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -269,6 +269,101 @@ bool PPCSymbolDB::LoadMap(const std::string& filename) return true; } +// Carefully load map files that might not be from exactly the right version +bool PPCSymbolDB::LoadBadMap(const std::string& filename) +{ + File::IOFile f(filename, "r"); + if (!f) + return false; + + bool started = false; + int good_count = 0, bad_count = 0; + + char line[512]; + while (fgets(line, 512, f.GetHandle())) + { + if (strlen(line) < 4) + continue; + + char temp[256]; + sscanf(line, "%255s", temp); + + if (strcmp(temp, "UNUSED") == 0) continue; + if (strcmp(temp, ".text") == 0) { started = true; continue; }; + if (strcmp(temp, ".init") == 0) { started = true; continue; }; + if (strcmp(temp, "Starting") == 0) continue; + if (strcmp(temp, "extab") == 0) continue; + if (strcmp(temp, ".ctors") == 0) break; //uh? + if (strcmp(temp, ".dtors") == 0) break; + if (strcmp(temp, ".rodata") == 0) continue; + if (strcmp(temp, ".data") == 0) continue; + if (strcmp(temp, ".sbss") == 0) continue; + if (strcmp(temp, ".sdata") == 0) continue; + if (strcmp(temp, ".sdata2") == 0) continue; + if (strcmp(temp, "address") == 0) continue; + if (strcmp(temp, "-----------------------") == 0) continue; + if (strcmp(temp, ".sbss2") == 0) break; + if (temp[1] == ']') continue; + + if (!started) continue; + + u32 address, vaddress, size, unknown; + char name[512]; + // some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")" + // instead of a space followed by a number followed by a space followed by a name + if (strlen(line) > 27 && line[27] != ' ' && strstr(line, "(entry of ")) + { + sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); + } + else + { + sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); + } + + const char *namepos = strstr(line, name); + if (namepos != nullptr) //would be odd if not :P + strcpy(name, namepos); + name[strlen(name) - 1] = 0; + + // we want the function names only .... TODO: or do we really? aren't we wasting information here? + for (size_t i = 0; i < strlen(name); i++) + { + if (name[i] == ' ') name[i] = 0x00; + if (name[i] == '(') name[i] = 0x00; + } + + // Check if this is a valid entry. + if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) + { + vaddress |= 0x80000000; + // check for BLR before function + u32 opcode = Memory::Read_Instruction(vaddress - 4); + if (opcode == 0x4e800020) + { + // check for BLR at end of function + opcode = Memory::Read_Instruction(vaddress + size - 4); + if (opcode == 0x4e800020) + { + AddKnownSymbol(vaddress, size, name); // ST_FUNCTION + ++good_count; + } + else + { + ++bad_count; + } + } + else + { + ++bad_count; + } + } + } + + Index(); + PanicAlertT("Loaded %d good functions, ignored %d bad functions", good_count, bad_count); + return true; +} + // =================================================== /* Save the map file and save a code file */ diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h index 09e01d13ed..a301721242 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -35,6 +35,7 @@ public: void FillInCallers(); bool LoadMap(const std::string& filename); + bool LoadBadMap(const std::string& filename); bool SaveMap(const std::string& filename, bool WithCodes = false) const; void PrintCalls(u32 funcAddr) const; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index fb69650567..822913d078 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -754,6 +754,7 @@ void CCodeWindow::UpdateButtonStates() GetMenuBar()->Enable(IDM_SAVEMAPFILE, Initialized); GetMenuBar()->Enable(IDM_LOADMAPFILEAS, Initialized); GetMenuBar()->Enable(IDM_SAVEMAPFILEAS, Initialized); + GetMenuBar()->Enable(IDM_LOADBADMAPFILE, Initialized); GetMenuBar()->Enable(IDM_SAVEMAPFILEWITHCODES, Initialized); GetMenuBar()->Enable(IDM_CREATESIGNATUREFILE, Initialized); GetMenuBar()->Enable(IDM_APPENDSIGNATUREFILE, Initialized); diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index cba74774da..b19d26fb74 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -155,8 +155,11 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) _("Try to load this game's function names automatically - but doesn't check .map files stored on the disc image yet.")); pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map"), _("Save the function names for each address to a .map file in your user settings map folder, named after the title id.")); + pSymbolsMenu->AppendSeparator(); pSymbolsMenu->Append(IDM_LOADMAPFILEAS, _("Choose symbol map file to load..."), _("Load any .map file containing the function names and addresses for this game.")); + pSymbolsMenu->Append(IDM_LOADBADMAPFILE, _("Load &bad map file..."), + _("Try to load a .map file that might be from a slightly different version.")); pSymbolsMenu->Append(IDM_SAVEMAPFILEAS, _("Save symbol map &as..."), _("Save the function names and addresses for this game as a .map file. If you want to open it in IDA pro, use the .idc script.")); pSymbolsMenu->AppendSeparator(); @@ -301,6 +304,23 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) NotifyMapLoaded(); } break; + case IDM_LOADBADMAPFILE: + { + const wxString path = wxFileSelector( + _("Load bad map file"), File::GetUserPath(D_MAPS_IDX), + title_id_str + ".map", ".map", + "Dolphin Map File (*.map)|*.map|All files (*.*)|*.*", + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + + if (!path.IsEmpty()) + { + g_symbolDB.LoadBadMap(WxStrToStr(path)); + Parent->StatusBarMessage("Loaded symbols from '%s'", path.c_str()); + } + HLE::PatchFunctions(); + NotifyMapLoaded(); + } + break; case IDM_SAVEMAPFILE: g_symbolDB.SaveMap(writable_map_file); break; diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.user b/Source/Core/DolphinWX/DolphinWX.vcxproj.user index ff24062772..4f062ae3a8 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.user +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.user @@ -1,4 +1,4 @@ - + @@ -6,4 +6,10 @@ $(BinaryOutputDir) WindowsLocalDebugger + + -d + + + -d + \ No newline at end of file diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 3df4f95996..20eda941d8 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -214,7 +214,7 @@ enum // Symbols IDM_CLEARSYMBOLS, IDM_SCANFUNCTIONS, - IDM_LOADMAPFILE, IDM_LOADMAPFILEAS, + IDM_LOADMAPFILE, IDM_LOADMAPFILEAS, IDM_LOADBADMAPFILE, IDM_SAVEMAPFILE, IDM_SAVEMAPFILEWITHCODES, IDM_SAVEMAPFILEAS, IDM_CREATESIGNATUREFILE, IDM_APPENDSIGNATUREFILE, From aa850c8eee0cda51cd86350ac147d1ae1e93d7c6 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Mon, 15 Dec 2014 11:11:35 +1030 Subject: [PATCH 3/8] Convert spaces to tabs in IDA Pro script. --- Tools/ReadDolphinMap.idc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Tools/ReadDolphinMap.idc b/Tools/ReadDolphinMap.idc index a092b4c35d..e5bd82543a 100644 --- a/Tools/ReadDolphinMap.idc +++ b/Tools/ReadDolphinMap.idc @@ -1,36 +1,36 @@ /* ReadDolphinMap.idc - Loads .map files generated by dolphin. - Carl Kenner, 2012 + Loads Dolphin .map files into IDA Pro. + Carl Kenner, 2014 */ #include static main(void) { - auto fh; - auto fname; - auto pusha, popa; - auto start, end; - auto success; - auto count; + auto fh; + auto fname; + auto pusha, popa; + auto start, end; + auto success; + auto count; auto line; auto ea; // column 1 auto name; // column 30 auto p; auto code; - fname = AskFile(0,"*.map","Load a .map file from Dolphin emulator..."); + fname = AskFile(0,"*.map","Load a .map file from Dolphin emulator..."); - fh = fopen(fname, "r"); - if (fh == 0) { + fh = fopen(fname, "r"); + if (fh == 0) { Message("Can't open %s\n", fname); return; - } + } - Message("Loading %s dolphin map file:\n", fname); + Message("Loading %s dolphin map file:\n", fname); - for (count = 0; 1; count++) { + for (count = 0; 1; count++) { line = readstr(fh); if (line == -1) break; @@ -57,6 +57,6 @@ static main(void) } } } - } - Message("Dolphin map file done.\n"); + } + Message("Dolphin map file done.\n"); } From f95f43fdde1a0c8f5181c1359314253e973b43ea Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Mon, 15 Dec 2014 11:34:18 +1030 Subject: [PATCH 4/8] Apparently c_str doesn't return a C str. --- Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index b19d26fb74..2adbb32b66 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -298,7 +298,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) if (!path.IsEmpty()) { g_symbolDB.LoadMap(WxStrToStr(path)); - Parent->StatusBarMessage("Loaded symbols from '%s'", path.c_str()); + Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); } HLE::PatchFunctions(); NotifyMapLoaded(); @@ -315,7 +315,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) if (!path.IsEmpty()) { g_symbolDB.LoadBadMap(WxStrToStr(path)); - Parent->StatusBarMessage("Loaded symbols from '%s'", path.c_str()); + Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); } HLE::PatchFunctions(); NotifyMapLoaded(); From dfd915eb535276088f9d9f8681b196b37bd11229 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Mon, 15 Dec 2014 18:42:07 +1030 Subject: [PATCH 5/8] Merge bad map file loading into the original function. --- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 105 +++--------------- Source/Core/Core/PowerPC/PPCSymbolDB.h | 3 +- .../Debugger/CodeWindowFunctions.cpp | 2 +- 3 files changed, 20 insertions(+), 90 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 1d6f5076ce..d9eb1adb9c 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -197,13 +197,15 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) // This one can load both leftover map files on game discs (like Zelda), and mapfiles // produced by SaveSymbolMap below. -bool PPCSymbolDB::LoadMap(const std::string& filename) +// bad=true means carefully load map files that might not be from exactly the right version +bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) { File::IOFile f(filename, "r"); if (!f) return false; bool started = false; + int good_count = 0, bad_count = 0; char line[512]; while (fgets(line, 512, f.GetHandle())) @@ -258,100 +260,28 @@ bool PPCSymbolDB::LoadMap(const std::string& filename) if (name[i] == '(') name[i] = 0x00; } - // Check if this is a valid entry. - if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) - { - AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION - } - } - - Index(); - return true; -} - -// Carefully load map files that might not be from exactly the right version -bool PPCSymbolDB::LoadBadMap(const std::string& filename) -{ - File::IOFile f(filename, "r"); - if (!f) - return false; - - bool started = false; - int good_count = 0, bad_count = 0; - - char line[512]; - while (fgets(line, 512, f.GetHandle())) - { - if (strlen(line) < 4) - continue; - - char temp[256]; - sscanf(line, "%255s", temp); - - if (strcmp(temp, "UNUSED") == 0) continue; - if (strcmp(temp, ".text") == 0) { started = true; continue; }; - if (strcmp(temp, ".init") == 0) { started = true; continue; }; - if (strcmp(temp, "Starting") == 0) continue; - if (strcmp(temp, "extab") == 0) continue; - if (strcmp(temp, ".ctors") == 0) break; //uh? - if (strcmp(temp, ".dtors") == 0) break; - if (strcmp(temp, ".rodata") == 0) continue; - if (strcmp(temp, ".data") == 0) continue; - if (strcmp(temp, ".sbss") == 0) continue; - if (strcmp(temp, ".sdata") == 0) continue; - if (strcmp(temp, ".sdata2") == 0) continue; - if (strcmp(temp, "address") == 0) continue; - if (strcmp(temp, "-----------------------") == 0) continue; - if (strcmp(temp, ".sbss2") == 0) break; - if (temp[1] == ']') continue; - - if (!started) continue; - - u32 address, vaddress, size, unknown; - char name[512]; - // some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")" - // instead of a space followed by a number followed by a space followed by a name - if (strlen(line) > 27 && line[27] != ' ' && strstr(line, "(entry of ")) - { - sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); - } - else - { - sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); - } - - const char *namepos = strstr(line, name); - if (namepos != nullptr) //would be odd if not :P - strcpy(name, namepos); - name[strlen(name) - 1] = 0; - - // we want the function names only .... TODO: or do we really? aren't we wasting information here? - for (size_t i = 0; i < strlen(name); i++) - { - if (name[i] == ' ') name[i] = 0x00; - if (name[i] == '(') name[i] = 0x00; - } - // Check if this is a valid entry. if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) { vaddress |= 0x80000000; - // check for BLR before function - u32 opcode = Memory::Read_Instruction(vaddress - 4); - if (opcode == 0x4e800020) + bool good = !bad; + if (!good) { - // check for BLR at end of function - opcode = Memory::Read_Instruction(vaddress + size - 4); + // check for BLR before function + u32 opcode = Memory::Read_Instruction(vaddress - 4); if (opcode == 0x4e800020) { - AddKnownSymbol(vaddress, size, name); // ST_FUNCTION - ++good_count; - } - else - { - ++bad_count; + // check for BLR at end of function + opcode = Memory::Read_Instruction(vaddress + size - 4); + if (opcode == 0x4e800020) + good = true; } } + if (good) + { + ++good_count; + AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION + } else { ++bad_count; @@ -360,7 +290,8 @@ bool PPCSymbolDB::LoadBadMap(const std::string& filename) } Index(); - PanicAlertT("Loaded %d good functions, ignored %d bad functions", good_count, bad_count); + if (bad) + PanicAlertT("Loaded %d good functions, ignored %d bad functions", good_count, bad_count); return true; } diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h index a301721242..fb24188efb 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -34,8 +34,7 @@ public: void FillInCallers(); - bool LoadMap(const std::string& filename); - bool LoadBadMap(const std::string& filename); + bool LoadMap(const std::string& filename, bool bad = false); bool SaveMap(const std::string& filename, bool WithCodes = false) const; void PrintCalls(u32 funcAddr) const; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index 2adbb32b66..e5f91692ee 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -314,7 +314,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) if (!path.IsEmpty()) { - g_symbolDB.LoadBadMap(WxStrToStr(path)); + g_symbolDB.LoadMap(WxStrToStr(path), true); Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); } HLE::PatchFunctions(); From cd5d354acc2a9e4f9fe9321f2fa693be692dd8f9 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Tue, 16 Dec 2014 01:42:54 +1030 Subject: [PATCH 6/8] Load 4 column map files like in American Mensa Academy. Unfortunately the map files in American Mensa Academy don't correspond to the release version. But at least now if other games use those map files we will be able to load them. --- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 75 ++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index d9eb1adb9c..24c1af5e2c 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -195,6 +195,23 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) } } +// The use case for handling bad map files is when you have a game with a map file on the disc, +// but you can't tell whether that map file is for the particular release version used in that game, +// or when you know that the map file is not for that build, but perhaps half the functions in the +// map file are still at the correct locations. Which are both common situations. It will load any +// function names and addresses that have a BLR before the start and at the end, but ignore any that +// don't, and then tell you how many were good and how many it ignored. That way you either find out +// it is all good and use it, find out it is partly good and use the good part, or find out that only +// a handful of functions lined up by coincidence and then you can clear the symbols. In the future I +// want to make it smarter, so it checks that there are no BLRs in the middle of the function +// (by checking the code length), and also make it cope with added functions in the middle or work +// based on the order of the functions and their approximate length. Currently that process has to be +// done manually and is very tedious. +// The use case for separate handling of map files that aren't bad is that you usually want to also +// load names that aren't functions(if included in the map file) without them being rejected as invalid. +// You can see discussion about these kinds of issues here : https://forums.oculus.com/viewtopic.php?f=42&t=11241&start=580 +// https://m2k2.taigaforum.com/post/metroid_prime_hacking_help_25.html#metroid_prime_hacking_help_25 + // This one can load both leftover map files on game discs (like Zelda), and mapfiles // produced by SaveSymbolMap below. // bad=true means carefully load map files that might not be from exactly the right version @@ -204,15 +221,23 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) if (!f) return false; - bool started = false; + // four columns are used in American Mensa Academy map files and perhaps other games + bool started = false, four_columns = false; int good_count = 0, bad_count = 0; char line[512]; while (fgets(line, 512, f.GetHandle())) { - if (strlen(line) < 4) + size_t length = strlen(line); + if (length < 4) continue; + if (length == 34 && strcmp(line, " address Size address offset\n") == 0) + { + four_columns = true; + continue; + } + char temp[256]; sscanf(line, "%255s", temp); @@ -235,13 +260,53 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) if (!started) continue; - u32 address, vaddress, size, unknown; - char name[512]; + u32 address, vaddress, size, offset, unknown; + char name[512], container[512]; + if (four_columns) + { + // sometimes there is no unknown number, and sometimes it is because it is an entry of something else + if (length > 37 && line[37]==' ') + { + unknown = 0; + sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name); + char *s = strstr(line, "(entry of "); + if (s) + { + sscanf(s + 10, "%511s", container); + char *s2 = (strchr(container, ')')); + if (s2 && container[0]!='.') + { + s2[0] = '\0'; + strcat(container, "::"); + strcat(container, name); + strcpy(name, container); + } + } + } + else + { + sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset, &unknown, name); + } + } // some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")" // instead of a space followed by a number followed by a space followed by a name - if (strlen(line) > 27 && line[27] != ' ' && strstr(line, "(entry of ")) + else if (length > 27 && line[27] != ' ' && strstr(line, "(entry of ")) { + unknown = 0; sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); + char *s = strstr(line, "(entry of "); + if (s) + { + sscanf(s + 10, "%511s", container); + char *s2 = (strchr(container, ')')); + if (s2 && container[0] != '.') + { + s2[0] = '\0'; + strcat(container, "::"); + strcat(container, name); + strcpy(name, container); + } + } } else { From 84ae817c180556badd1a810fceff4c4168672541 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Tue, 16 Dec 2014 05:30:43 +1030 Subject: [PATCH 7/8] Remove white space at ends of lines. --- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 24c1af5e2c..ef4863812b 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -195,16 +195,16 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) } } -// The use case for handling bad map files is when you have a game with a map file on the disc, +// The use case for handling bad map files is when you have a game with a map file on the disc, // but you can't tell whether that map file is for the particular release version used in that game, // or when you know that the map file is not for that build, but perhaps half the functions in the -// map file are still at the correct locations. Which are both common situations. It will load any -// function names and addresses that have a BLR before the start and at the end, but ignore any that -// don't, and then tell you how many were good and how many it ignored. That way you either find out -// it is all good and use it, find out it is partly good and use the good part, or find out that only -// a handful of functions lined up by coincidence and then you can clear the symbols. In the future I -// want to make it smarter, so it checks that there are no BLRs in the middle of the function -// (by checking the code length), and also make it cope with added functions in the middle or work +// map file are still at the correct locations. Which are both common situations. It will load any +// function names and addresses that have a BLR before the start and at the end, but ignore any that +// don't, and then tell you how many were good and how many it ignored. That way you either find out +// it is all good and use it, find out it is partly good and use the good part, or find out that only +// a handful of functions lined up by coincidence and then you can clear the symbols. In the future I +// want to make it smarter, so it checks that there are no BLRs in the middle of the function +// (by checking the code length), and also make it cope with added functions in the middle or work // based on the order of the functions and their approximate length. Currently that process has to be // done manually and is very tedious. // The use case for separate handling of map files that aren't bad is that you usually want to also From 6e7eb52211844727bdf9f665630273ea109a1589 Mon Sep 17 00:00:00 2001 From: CarlKenner Date: Wed, 17 Dec 2014 00:11:05 +1030 Subject: [PATCH 8/8] Rename menu items, stop using PanicAlertT, remove -d when running from visual studio. I accidentally committed my addition of the -d option that I used for testing, now it's fixed. --- Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 2 +- Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp | 6 +++--- Source/Core/DolphinWX/DolphinWX.vcxproj.user | 6 ------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index ef4863812b..55d9cb1e59 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -356,7 +356,7 @@ bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) Index(); if (bad) - PanicAlertT("Loaded %d good functions, ignored %d bad functions", good_count, bad_count); + SuccessAlertT("Loaded %d good functions, ignored %d bad functions.", good_count, bad_count); return true; } diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index e5f91692ee..1bf48b523e 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -156,7 +156,7 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map"), _("Save the function names for each address to a .map file in your user settings map folder, named after the title id.")); pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_LOADMAPFILEAS, _("Choose symbol map file to load..."), + pSymbolsMenu->Append(IDM_LOADMAPFILEAS, _("Load &other map file..."), _("Load any .map file containing the function names and addresses for this game.")); pSymbolsMenu->Append(IDM_LOADBADMAPFILE, _("Load &bad map file..."), _("Try to load a .map file that might be from a slightly different version.")); @@ -176,9 +176,9 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) _("Create a .dsy file that can be used to recognise these same functions in other games.")); pSymbolsMenu->Append(IDM_APPENDSIGNATUREFILE, _("Append to &existing signature file..."), _("Add any named functions missing from a .dsy file, so it can also recognise these additional functions in other games.")); - pSymbolsMenu->Append(IDM_COMBINESIGNATUREFILES, _("Combine &2 signature files..."), + pSymbolsMenu->Append(IDM_COMBINESIGNATUREFILES, _("Combine two signature files..."), _("Make a new .dsy file which can recognise more functions, by combining two existing files. The first input file has priority.")); - pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _("&Use signature file..."), + pSymbolsMenu->Append(IDM_USESIGNATUREFILE, _("Apply signat&ure file..."), _("Must use Generate symbol map first! Recognise names of any standard library functions used in multiple games, by loading them from a .dsy file.")); pSymbolsMenu->AppendSeparator(); pSymbolsMenu->Append(IDM_PATCHHLEFUNCTIONS, _("&Patch HLE functions")); diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.user b/Source/Core/DolphinWX/DolphinWX.vcxproj.user index 4f062ae3a8..aa15c4df30 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.user +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.user @@ -6,10 +6,4 @@ $(BinaryOutputDir) WindowsLocalDebugger - - -d - - - -d - \ No newline at end of file