|
|
@@ -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) {
|
|
|
if (command.starts_with("TStatus")) {
|
|
|
// no tracepoint support
|
|
|
@@ -573,21 +687,10 @@ void GDBStub::HandleQuery(std::string_view command) {
|
|
|
const auto target_xml{arch->GetTargetXML()};
|
|
|
SendReply(PaginateBuffer(target_xml, command.substr(30)));
|
|
|
} else if (command.starts_with("Offsets")) {
|
|
|
- Loader::AppLoader::Modules modules;
|
|
|
- system.GetAppLoader().ReadNSOModules(modules);
|
|
|
-
|
|
|
- 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())));
|
|
|
- }
|
|
|
+ const auto main_offset = FindMainModuleEntrypoint(system);
|
|
|
+ SendReply(fmt::format("TextSeg={:x}", main_offset));
|
|
|
} else if (command.starts_with("Xfer:libraries:read::")) {
|
|
|
- Loader::AppLoader::Modules modules;
|
|
|
- system.GetAppLoader().ReadNSOModules(modules);
|
|
|
+ auto modules = FindModules(system);
|
|
|
|
|
|
std::string buffer;
|
|
|
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) {
|
|
|
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
|
|
|
std::string reply;
|
|
|
@@ -784,8 +856,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
|
|
|
reply = "Fastmem is not enabled.\n";
|
|
|
}
|
|
|
} else if (command_str == "get info") {
|
|
|
- Loader::AppLoader::Modules modules;
|
|
|
- system.GetAppLoader().ReadNSOModules(modules);
|
|
|
+ auto modules = FindModules(system);
|
|
|
|
|
|
reply = fmt::format("Process: {:#x} ({})\n"
|
|
|
"Program Id: {:#018x}\n",
|