Merge pull request #13247 from sepalani/debug-map-ranges

PPCSymbolDB: Refactor SymbolMap Save/Load
This commit is contained in:
Admiral H. Curtiss 2025-01-12 14:26:04 +01:00 committed by GitHub
commit b0e5ebc80d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -6,11 +6,11 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <ranges>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include <vector>
#include <fmt/format.h> #include <fmt/format.h>
@ -18,6 +18,7 @@
#include "Common/IOFile.h" #include "Common/IOFile.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Unreachable.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/Debugger/DebugInterface.h" #include "Core/Debugger/DebugInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
@ -310,7 +311,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
continue; continue;
column_count = 2; column_count = 2;
// Three columns format: // Three columns format (with optional alignment):
// Starting Virtual // Starting Virtual
// address Size address // address Size address
// ----------------------- // -----------------------
@ -319,7 +320,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
else else
iss.str(""); iss.str("");
// Four columns format: // Four columns format (with optional alignment):
// Starting Virtual File // Starting Virtual File
// address Size address offset // address Size address offset
// --------------------------------- // ---------------------------------
@ -327,85 +328,77 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
column_count = 4; column_count = 4;
} }
u32 address, vaddress, size, offset, alignment; u32 address;
char name[512], container[512]; u32 vaddress;
if (column_count == 4) u32 size = 0;
{ u32 offset = 0;
// sometimes there is no alignment value, and sometimes it is because it is an entry of u32 alignment = 0;
// something else char name[512]{};
if (length > 37 && line[37] == ' ') static constexpr char ENTRY_OF_STRING[] = " (entry of ";
static constexpr std::string_view ENTRY_OF_VIEW(ENTRY_OF_STRING);
auto parse_entry_of = [](char* name) {
if (char* s1 = strstr(name, ENTRY_OF_STRING); s1 != nullptr)
{ {
alignment = 0; char container[512];
sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name); char* ptr = s1 + ENTRY_OF_VIEW.size();
char* s = strstr(line, "(entry of "); sscanf(ptr, "%511s", container);
if (s) // Skip sections, those start with a dot, e.g. (entry of .text)
if (char* s2 = strchr(container, ')'); s2 != nullptr && *container != '.')
{ {
sscanf(s + 10, "%511s", container); ptr += strlen(container);
char* s2 = (strchr(container, ')')); // Preserve data after the entry part, usually it contains object names
if (s2 && container[0] != '.') strcpy(s1, ptr);
{ *s2 = '\0';
s2[0] = '\0'; strcat(container, "::");
strcat(container, "::"); strcat(container, name);
strcat(container, name); strcpy(name, container);
strcpy(name, container);
}
} }
} }
else };
{ auto was_alignment = [](const char* name) {
sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset, return *name == ' ' || (*name >= '0' && *name <= '9');
&alignment, name); };
} auto parse_alignment = [](char* name, u32* alignment) {
} const std::string buffer(StripWhitespace(name));
else if (column_count == 3) return sscanf(buffer.c_str(), "%i %511[^\r\n]", alignment, name);
};
switch (column_count)
{ {
case 4:
// sometimes there is no alignment value, and sometimes it is because it is an entry of
// something else
sscanf(line, "%08x %08x %08x %08x %511[^\r\n]", &address, &size, &vaddress, &offset, name);
if (was_alignment(name))
parse_alignment(name, &alignment);
// The `else` statement was omitted to handle symbol already saved in Dolphin symbol map
// since it doesn't omit the alignment on save for such case.
parse_entry_of(name);
break;
case 3:
// some entries in the table have a function name followed by " (entry of " followed by a // some entries in the table have a function name followed by " (entry of " followed by a
// container name, followed by ")" // container name, followed by ")"
// instead of a space followed by a number followed by a space followed by a name // instead of a space followed by a number followed by a space followed by a name
if (length > 27 && line[27] != ' ' && strstr(line, "(entry of ")) sscanf(line, "%08x %08x %08x %511[^\r\n]", &address, &size, &vaddress, name);
{ if (was_alignment(name))
alignment = 0; parse_alignment(name, &alignment);
sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); // The `else` statement was omitted to handle symbol already saved in Dolphin symbol map
char* s = strstr(line, "(entry of "); // since it doesn't omit the alignment on save for such case.
if (s) parse_entry_of(name);
{ break;
sscanf(s + 10, "%511s", container); case 2:
char* s2 = (strchr(container, ')')); sscanf(line, "%08x %511[^\r\n]", &address, name);
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, &alignment, name);
}
}
else if (column_count == 2)
{
sscanf(line, "%08x %511s", &address, name);
vaddress = address; vaddress = address;
size = 0; break;
} default:
else // Should never happen
{ Common::Unreachable();
break; break;
} }
const char* namepos = strstr(line, name);
if (namepos != nullptr) // would be odd if not :P
strcpy(name, namepos);
name[strlen(name) - 1] = 0;
if (name[strlen(name) - 1] == '\r')
name[strlen(name) - 1] = 0;
// Split the current name string into separate parts, and get the object name // Split the current name string into separate parts, and get the object name
// if it exists. // if it exists.
const std::vector<std::string> parts = SplitString(name, '\t'); const std::vector<std::string> parts = SplitString(name, '\t');
const std::string name_string(StripWhitespace(parts[0])); const std::string name_string(StripWhitespace(parts.size() > 0 ? parts[0] : name));
const std::string object_filename_string = const std::string object_filename_string =
parts.size() > 1 ? std::string(StripWhitespace(parts[1])) : ""; parts.size() > 1 ? std::string(StripWhitespace(parts[1])) : "";
@ -466,42 +459,38 @@ bool PPCSymbolDB::SaveSymbolMap(const std::string& filename) const
if (!f) if (!f)
return false; return false;
std::vector<const Common::Symbol*> function_symbols;
std::vector<const Common::Symbol*> data_symbols;
for (const auto& function : m_functions)
{
const Common::Symbol& symbol = function.second;
if (symbol.type == Common::Symbol::Type::Function)
function_symbols.push_back(&symbol);
else
data_symbols.push_back(&symbol);
}
// Write .text section // Write .text section
auto function_symbols =
m_functions |
std::views::filter([](auto f) { return f.second.type == Common::Symbol::Type::Function; }) |
std::views::transform([](auto f) { return f.second; });
f.WriteString(".text section layout\n"); f.WriteString(".text section layout\n");
for (const auto& symbol : function_symbols) for (const auto& symbol : function_symbols)
{ {
// Write symbol address, size, virtual address, alignment, name // Write symbol address, size, virtual address, alignment, name
std::string line = fmt::format("{0:08x} {1:06x} {2:08x} {3} {4}", symbol->address, symbol->size, std::string line = fmt::format("{:08x} {:06x} {:08x} {} {}", symbol.address, symbol.size,
symbol->address, 0, symbol->name); symbol.address, 0, symbol.name);
// Also write the object name if it exists // Also write the object name if it exists
if (!symbol->object_name.empty()) if (!symbol.object_name.empty())
line += fmt::format(" \t{0}", symbol->object_name); line += fmt::format(" \t{0}", symbol.object_name);
line += "\n"; line += "\n";
f.WriteString(line); f.WriteString(line);
} }
// Write .data section // Write .data section
auto data_symbols =
m_functions |
std::views::filter([](auto f) { return f.second.type == Common::Symbol::Type::Data; }) |
std::views::transform([](auto f) { return f.second; });
f.WriteString("\n.data section layout\n"); f.WriteString("\n.data section layout\n");
for (const auto& symbol : data_symbols) for (const auto& symbol : data_symbols)
{ {
// Write symbol address, size, virtual address, alignment, name // Write symbol address, size, virtual address, alignment, name
std::string line = fmt::format("{0:08x} {1:06x} {2:08x} {3} {4}", symbol->address, symbol->size, std::string line = fmt::format("{:08x} {:06x} {:08x} {} {}", symbol.address, symbol.size,
symbol->address, 0, symbol->name); symbol.address, 0, symbol.name);
// Also write the object name if it exists // Also write the object name if it exists
if (!symbol->object_name.empty()) if (!symbol.object_name.empty())
line += fmt::format(" \t{0}", symbol->object_name); line += fmt::format(" \t{0}", symbol.object_name);
line += "\n"; line += "\n";
f.WriteString(line); f.WriteString(line);
} }