diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/debugger/gdbstub.cpp | 243 | ||||
-rw-r--r-- | src/core/debugger/gdbstub_arch.cpp | 72 | ||||
-rw-r--r-- | src/core/debugger/gdbstub_arch.h | 1 |
3 files changed, 44 insertions, 272 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 148dd3e39..66e46c4ba 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -16,6 +16,7 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/arm/arm_interface.h" +#include "core/arm/debug.h" #include "core/core.h" #include "core/debugger/gdbstub.h" #include "core/debugger/gdbstub_arch.h" @@ -310,7 +311,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const auto mem{Common::HexStringToVector(mem_substr, false)}; if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { - system.InvalidateCpuInstructionCacheRange(addr, size); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); SendReply(GDB_STUB_REPLY_OK); } else { SendReply(GDB_STUB_REPLY_ERR); @@ -363,7 +364,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { case BreakpointType::Software: replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); - system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); success = true; break; case BreakpointType::WriteWatch: @@ -411,7 +412,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { const auto orig_insn{replaced_instructions.find(addr)}; if (orig_insn != replaced_instructions.end()) { system.ApplicationMemory().Write32(addr, orig_insn->second); - system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); replaced_instructions.erase(addr); success = true; } @@ -442,114 +443,6 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { } } -// Structure offsets are from Atmosphere -// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp - -static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, - const Kernel::KThread& thread) { - // Read thread type from TLS - const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)}; - const VAddr argument_thread_type{thread.GetArgument()}; - - if (argument_thread_type && tls_thread_type != argument_thread_type) { - // Probably not created by nnsdk, no name available. - return std::nullopt; - } - - if (!tls_thread_type) { - return std::nullopt; - } - - const u16 version{memory.Read16(tls_thread_type + 0x26)}; - VAddr name_pointer{}; - if (version == 1) { - name_pointer = memory.Read32(tls_thread_type + 0xe4); - } else { - name_pointer = memory.Read32(tls_thread_type + 0xe8); - } - - if (!name_pointer) { - // No name provided. - return std::nullopt; - } - - return memory.ReadCString(name_pointer, 256); -} - -static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, - const Kernel::KThread& thread) { - // Read thread type from TLS - const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)}; - const VAddr argument_thread_type{thread.GetArgument()}; - - if (argument_thread_type && tls_thread_type != argument_thread_type) { - // Probably not created by nnsdk, no name available. - return std::nullopt; - } - - if (!tls_thread_type) { - return std::nullopt; - } - - const u16 version{memory.Read16(tls_thread_type + 0x46)}; - VAddr name_pointer{}; - if (version == 1) { - name_pointer = memory.Read64(tls_thread_type + 0x1a0); - } else { - name_pointer = memory.Read64(tls_thread_type + 0x1a8); - } - - if (!name_pointer) { - // No name provided. - return std::nullopt; - } - - return memory.ReadCString(name_pointer, 256); -} - -static std::optional<std::string> GetThreadName(Core::System& system, - const Kernel::KThread& thread) { - if (system.ApplicationProcess()->Is64Bit()) { - return GetNameFromThreadType64(system.ApplicationMemory(), thread); - } else { - return GetNameFromThreadType32(system.ApplicationMemory(), thread); - } -} - -static std::string_view GetThreadWaitReason(const Kernel::KThread& thread) { - switch (thread.GetWaitReasonForDebugging()) { - case Kernel::ThreadWaitReasonForDebugging::Sleep: - return "Sleep"; - case Kernel::ThreadWaitReasonForDebugging::IPC: - return "IPC"; - case Kernel::ThreadWaitReasonForDebugging::Synchronization: - return "Synchronization"; - case Kernel::ThreadWaitReasonForDebugging::ConditionVar: - return "ConditionVar"; - case Kernel::ThreadWaitReasonForDebugging::Arbitration: - return "Arbitration"; - case Kernel::ThreadWaitReasonForDebugging::Suspended: - return "Suspended"; - default: - return "Unknown"; - } -} - -static std::string GetThreadState(const Kernel::KThread& thread) { - switch (thread.GetState()) { - case Kernel::ThreadState::Initialized: - return "Initialized"; - case Kernel::ThreadState::Waiting: - return fmt::format("Waiting ({})", GetThreadWaitReason(thread)); - case Kernel::ThreadState::Runnable: - return "Runnable"; - case Kernel::ThreadState::Terminated: - return "Terminated"; - default: - return "Unknown"; - } -} - static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { const auto amount{request.substr(request.find(',') + 1)}; const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))}; @@ -562,120 +455,6 @@ 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 @@ -687,10 +466,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")) { - const auto main_offset = FindMainModuleEntrypoint(system); - SendReply(fmt::format("TextSeg={:x}", main_offset)); + const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); + SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); } else if (command.starts_with("Xfer:libraries:read::")) { - auto modules = FindModules(system); + auto modules = Core::FindModules(system.ApplicationProcess()); std::string buffer; buffer += R"(<?xml version="1.0"?>)"; @@ -720,14 +499,14 @@ void GDBStub::HandleQuery(std::string_view command) { const auto& threads = system.ApplicationProcess()->GetThreadList(); for (const auto& thread : threads) { - auto thread_name{GetThreadName(system, thread)}; + auto thread_name{Core::GetThreadName(&thread)}; if (!thread_name) { thread_name = fmt::format("Thread {:d}", thread.GetThreadId()); } buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", thread.GetThreadId(), thread.GetActiveCore(), - EscapeXML(*thread_name), GetThreadState(thread)); + EscapeXML(*thread_name), GetThreadState(&thread)); } buffer += "</threads>"; @@ -856,7 +635,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { reply = "Fastmem is not enabled.\n"; } } else if (command_str == "get info") { - auto modules = FindModules(system); + auto modules = Core::FindModules(process); reply = fmt::format("Process: {:#x} ({})\n" "Program Id: {:#018x}\n", @@ -880,7 +659,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { for (const auto& [vaddr, name] : modules) { reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, - GetModuleEnd(page_table, vaddr), name); + GetInteger(Core::GetModuleEnd(process, vaddr)), name); } } else if (command_str == "get mappings") { reply = "Mappings:\n"; diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp index 75c94a91a..f2a407dc8 100644 --- a/src/core/debugger/gdbstub_arch.cpp +++ b/src/core/debugger/gdbstub_arch.cpp @@ -24,21 +24,6 @@ static std::string ValueToHex(const T value) { return Common::HexToString(mem); } -template <typename T> -static T GetSIMDRegister(const std::array<u32, 64>& simd_regs, size_t offset) { - static_assert(std::is_trivially_copyable_v<T>); - T value{}; - std::memcpy(&value, reinterpret_cast<const u8*>(simd_regs.data()) + sizeof(T) * offset, - sizeof(T)); - return value; -} - -template <typename T> -static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const T value) { - static_assert(std::is_trivially_copyable_v<T>); - std::memcpy(reinterpret_cast<u8*>(simd_regs.data()) + sizeof(T) * offset, &value, sizeof(T)); -} - // For sample XML files see the GDB source /gdb/features // This XML defines what the registers are for this specific ARM device std::string_view GDBStubA64::GetTargetXML() const { @@ -184,12 +169,16 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const return ""; } - const auto& context{thread->GetContext64()}; - const auto& gprs{context.cpu_registers}; - const auto& fprs{context.vector_registers}; + const auto& context{thread->GetContext()}; + const auto& gprs{context.r}; + const auto& fprs{context.v}; - if (id < SP_REGISTER) { + if (id < FP_REGISTER) { return ValueToHex(gprs[id]); + } else if (id == FP_REGISTER) { + return ValueToHex(context.fp); + } else if (id == LR_REGISTER) { + return ValueToHex(context.lr); } else if (id == SP_REGISTER) { return ValueToHex(context.sp); } else if (id == PC_REGISTER) { @@ -212,10 +201,14 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v return; } - auto& context{thread->GetContext64()}; + auto& context{thread->GetContext()}; - if (id < SP_REGISTER) { - context.cpu_registers[id] = HexToValue<u64>(value); + if (id < FP_REGISTER) { + context.r[id] = HexToValue<u64>(value); + } else if (id == FP_REGISTER) { + context.fp = HexToValue<u64>(value); + } else if (id == LR_REGISTER) { + context.lr = HexToValue<u64>(value); } else if (id == SP_REGISTER) { context.sp = HexToValue<u64>(value); } else if (id == PC_REGISTER) { @@ -223,7 +216,7 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v } else if (id == PSTATE_REGISTER) { context.pstate = HexToValue<u32>(value); } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { - context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value); + context.v[id - Q0_REGISTER] = HexToValue<u128>(value); } else if (id == FPSR_REGISTER) { context.fpsr = HexToValue<u32>(value); } else if (id == FPCR_REGISTER) { @@ -381,22 +374,20 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const return ""; } - const auto& context{thread->GetContext32()}; - const auto& gprs{context.cpu_registers}; - const auto& fprs{context.extension_registers}; + const auto& context{thread->GetContext()}; + const auto& gprs{context.r}; + const auto& fprs{context.v}; if (id <= PC_REGISTER) { - return ValueToHex(gprs[id]); + return ValueToHex(static_cast<u32>(gprs[id])); } else if (id == CPSR_REGISTER) { - return ValueToHex(context.cpsr); + return ValueToHex(context.pstate); } else if (id >= D0_REGISTER && id < Q0_REGISTER) { - const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)}; - return ValueToHex(dN); + return ValueToHex(fprs[id - D0_REGISTER][0]); } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { - const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)}; - return ValueToHex(qN); + return ValueToHex(fprs[id - Q0_REGISTER]); } else if (id == FPSCR_REGISTER) { - return ValueToHex(context.fpscr); + return ValueToHex(context.fpcr | context.fpsr); } else { return ""; } @@ -407,19 +398,20 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v return; } - auto& context{thread->GetContext32()}; - auto& fprs{context.extension_registers}; + auto& context{thread->GetContext()}; + auto& fprs{context.v}; if (id <= PC_REGISTER) { - context.cpu_registers[id] = HexToValue<u32>(value); + context.r[id] = HexToValue<u32>(value); } else if (id == CPSR_REGISTER) { - context.cpsr = HexToValue<u32>(value); + context.pstate = HexToValue<u32>(value); } else if (id >= D0_REGISTER && id < Q0_REGISTER) { - PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value)); + fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0}; } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { - PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value)); + fprs[id - Q0_REGISTER] = HexToValue<u128>(value); } else if (id == FPSCR_REGISTER) { - context.fpscr = HexToValue<u32>(value); + context.fpcr = HexToValue<u32>(value); + context.fpsr = HexToValue<u32>(value); } } diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h index 34530c788..d53714d69 100644 --- a/src/core/debugger/gdbstub_arch.h +++ b/src/core/debugger/gdbstub_arch.h @@ -36,6 +36,7 @@ public: u32 BreakpointInstruction() const override; private: + static constexpr u32 FP_REGISTER = 29; static constexpr u32 LR_REGISTER = 30; static constexpr u32 SP_REGISTER = 31; static constexpr u32 PC_REGISTER = 32; |