Merge pull request #12003 from liamwhite/read-modules
gdbstub: read module information from memory layout
This commit is contained in:
commit
5f6666a7cd
|
@ -562,6 +562,120 @@ static std::string PaginateBuffer(std::string_view buffer, std::string_view requ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) {
|
||||||
|
Kernel::KMemoryInfo mem_info;
|
||||||
|
Kernel::Svc::MemoryInfo svc_mem_info;
|
||||||
|
Kernel::Svc::PageInfo page_info;
|
||||||
|
VAddr cur_addr{base};
|
||||||
|
|
||||||
|
// Expect: r-x Code (.text)
|
||||||
|
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
||||||
|
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
||||||
|
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
||||||
|
if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
|
||||||
|
svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
|
||||||
|
return cur_addr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect: r-- Code (.rodata)
|
||||||
|
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
||||||
|
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
||||||
|
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
||||||
|
if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
|
||||||
|
svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
|
||||||
|
return cur_addr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect: rw- CodeData (.data)
|
||||||
|
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
||||||
|
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
||||||
|
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
||||||
|
return cur_addr - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Loader::AppLoader::Modules FindModules(Core::System& system) {
|
||||||
|
Loader::AppLoader::Modules modules;
|
||||||
|
|
||||||
|
auto& page_table = system.ApplicationProcess()->GetPageTable();
|
||||||
|
auto& memory = system.ApplicationMemory();
|
||||||
|
VAddr cur_addr = 0;
|
||||||
|
|
||||||
|
// Look for executable sections in Code or AliasCode regions.
|
||||||
|
while (true) {
|
||||||
|
Kernel::KMemoryInfo mem_info{};
|
||||||
|
Kernel::Svc::PageInfo page_info{};
|
||||||
|
R_ASSERT(
|
||||||
|
page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
||||||
|
auto svc_mem_info = mem_info.GetSvcMemoryInfo();
|
||||||
|
|
||||||
|
if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute &&
|
||||||
|
(svc_mem_info.state == Kernel::Svc::MemoryState::Code ||
|
||||||
|
svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) {
|
||||||
|
// Try to read the module name from its path.
|
||||||
|
constexpr s32 PathLengthMax = 0x200;
|
||||||
|
struct {
|
||||||
|
u32 zero;
|
||||||
|
s32 path_length;
|
||||||
|
std::array<char, PathLengthMax> path;
|
||||||
|
} module_path;
|
||||||
|
|
||||||
|
if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path,
|
||||||
|
sizeof(module_path))) {
|
||||||
|
if (module_path.zero == 0 && module_path.path_length > 0) {
|
||||||
|
// Truncate module name.
|
||||||
|
module_path.path[PathLengthMax - 1] = '\0';
|
||||||
|
|
||||||
|
// Ignore leading directories.
|
||||||
|
char* path_pointer = module_path.path.data();
|
||||||
|
|
||||||
|
for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) &&
|
||||||
|
module_path.path[i] != '\0';
|
||||||
|
i++) {
|
||||||
|
if (module_path.path[i] == '/' || module_path.path[i] == '\\') {
|
||||||
|
path_pointer = module_path.path.data() + i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert output.
|
||||||
|
modules.emplace(svc_mem_info.base_address, path_pointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're done.
|
||||||
|
const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
|
||||||
|
if (next_address <= cur_addr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_addr = next_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VAddr FindMainModuleEntrypoint(Core::System& system) {
|
||||||
|
Loader::AppLoader::Modules modules;
|
||||||
|
system.GetAppLoader().ReadNSOModules(modules);
|
||||||
|
|
||||||
|
// Do we have a module named main?
|
||||||
|
const auto main = std::find_if(modules.begin(), modules.end(),
|
||||||
|
[](const auto& key) { return key.second == "main"; });
|
||||||
|
|
||||||
|
if (main != modules.end()) {
|
||||||
|
return main->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have any loaded executable sections?
|
||||||
|
modules = FindModules(system);
|
||||||
|
if (!modules.empty()) {
|
||||||
|
return modules.begin()->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a last resort, use the start of the code region.
|
||||||
|
return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart());
|
||||||
|
}
|
||||||
|
|
||||||
void GDBStub::HandleQuery(std::string_view command) {
|
void GDBStub::HandleQuery(std::string_view command) {
|
||||||
if (command.starts_with("TStatus")) {
|
if (command.starts_with("TStatus")) {
|
||||||
// no tracepoint support
|
// no tracepoint support
|
||||||
|
@ -573,21 +687,10 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||||
const auto target_xml{arch->GetTargetXML()};
|
const auto target_xml{arch->GetTargetXML()};
|
||||||
SendReply(PaginateBuffer(target_xml, command.substr(30)));
|
SendReply(PaginateBuffer(target_xml, command.substr(30)));
|
||||||
} else if (command.starts_with("Offsets")) {
|
} else if (command.starts_with("Offsets")) {
|
||||||
Loader::AppLoader::Modules modules;
|
const auto main_offset = FindMainModuleEntrypoint(system);
|
||||||
system.GetAppLoader().ReadNSOModules(modules);
|
SendReply(fmt::format("TextSeg={:x}", main_offset));
|
||||||
|
|
||||||
const auto main = std::find_if(modules.begin(), modules.end(),
|
|
||||||
[](const auto& key) { return key.second == "main"; });
|
|
||||||
if (main != modules.end()) {
|
|
||||||
SendReply(fmt::format("TextSeg={:x}", main->first));
|
|
||||||
} else {
|
|
||||||
SendReply(fmt::format(
|
|
||||||
"TextSeg={:x}",
|
|
||||||
GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart())));
|
|
||||||
}
|
|
||||||
} else if (command.starts_with("Xfer:libraries:read::")) {
|
} else if (command.starts_with("Xfer:libraries:read::")) {
|
||||||
Loader::AppLoader::Modules modules;
|
auto modules = FindModules(system);
|
||||||
system.GetAppLoader().ReadNSOModules(modules);
|
|
||||||
|
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
buffer += R"(<?xml version="1.0"?>)";
|
buffer += R"(<?xml version="1.0"?>)";
|
||||||
|
@ -727,37 +830,6 @@ static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) {
|
|
||||||
Kernel::KMemoryInfo mem_info;
|
|
||||||
Kernel::Svc::MemoryInfo svc_mem_info;
|
|
||||||
Kernel::Svc::PageInfo page_info;
|
|
||||||
VAddr cur_addr{base};
|
|
||||||
|
|
||||||
// Expect: r-x Code (.text)
|
|
||||||
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
|
||||||
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
|
||||||
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
|
||||||
if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
|
|
||||||
svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
|
|
||||||
return cur_addr - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expect: r-- Code (.rodata)
|
|
||||||
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
|
||||||
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
|
||||||
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
|
||||||
if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
|
|
||||||
svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
|
|
||||||
return cur_addr - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expect: rw- CodeData (.data)
|
|
||||||
R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
|
|
||||||
svc_mem_info = mem_info.GetSvcMemoryInfo();
|
|
||||||
cur_addr = svc_mem_info.base_address + svc_mem_info.size;
|
|
||||||
return cur_addr - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDBStub::HandleRcmd(const std::vector<u8>& command) {
|
void GDBStub::HandleRcmd(const std::vector<u8>& command) {
|
||||||
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
|
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
|
||||||
std::string reply;
|
std::string reply;
|
||||||
|
@ -784,8 +856,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
|
||||||
reply = "Fastmem is not enabled.\n";
|
reply = "Fastmem is not enabled.\n";
|
||||||
}
|
}
|
||||||
} else if (command_str == "get info") {
|
} else if (command_str == "get info") {
|
||||||
Loader::AppLoader::Modules modules;
|
auto modules = FindModules(system);
|
||||||
system.GetAppLoader().ReadNSOModules(modules);
|
|
||||||
|
|
||||||
reply = fmt::format("Process: {:#x} ({})\n"
|
reply = fmt::format("Process: {:#x} ({})\n"
|
||||||
"Program Id: {:#018x}\n",
|
"Program Id: {:#018x}\n",
|
||||||
|
|
Loading…
Reference in a new issue