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..55d9cb1e59 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; } @@ -195,22 +195,49 @@ 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. -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; + // 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); @@ -233,9 +260,58 @@ bool PPCSymbolDB::LoadMap(const std::string& filename) if (!started) continue; - u32 address, vaddress, size, unknown; - char name[512]; - sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); + 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 + 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 + { + 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,13 +326,37 @@ 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 + vaddress |= 0x80000000; + bool good = !bad; + if (!good) + { + // 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) + good = true; + } + } + if (good) + { + ++good_count; + AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION + } + else + { + ++bad_count; + } } } Index(); + if (bad) + SuccessAlertT("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 09e01d13ed..fb24188efb 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -34,7 +34,7 @@ public: void FillInCallers(); - bool LoadMap(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/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..822913d078 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -752,8 +752,13 @@ 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_LOADBADMAPFILE, 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..1bf48b523e 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -146,11 +146,22 @@ 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->AppendSeparator(); + 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.")); + 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 +172,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 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, _("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")); pSymbolsMenu->Append(IDM_RENAME_SYMBOLS, _("&Rename symbols from file...")); @@ -222,9 +239,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 +258,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) { db.Apply(&g_symbolDB); Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB); + db.List(); } else { @@ -268,9 +287,55 @@ 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'", WxStrToStr(path).c_str()); + } + HLE::PatchFunctions(); + 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.LoadMap(WxStrToStr(path), true); + Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(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 +388,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 +432,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 +440,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/DolphinWX.vcxproj.user b/Source/Core/DolphinWX/DolphinWX.vcxproj.user index ff24062772..aa15c4df30 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.user +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.user @@ -1,4 +1,4 @@ - + diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 42ae34b87a..20eda941d8 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_LOADBADMAPFILE, + 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..e5bd82543a --- /dev/null +++ b/Tools/ReadDolphinMap.idc @@ -0,0 +1,62 @@ +/* ReadDolphinMap.idc + + 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 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"); +}