diff options
| author | Rodrigo Locatti <reinuseslisp@airmail.cc> | 2020-11-27 19:29:59 -0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-27 19:29:59 -0300 | 
| commit | 1dbe39f7a25357b40541ca536698cb09bb7df4ff (patch) | |
| tree | 285ffb3801aa773cb3537f77153a9e432390f6b8 | |
| parent | f397edff0ea6711bac15cfe47a0157e9b790b8bb (diff) | |
| parent | 5bc4eabe36b7ef4dcd5ad8db1e944705655be432 (diff) | |
Merge pull request #5028 from lioncash/final-system
core: Eliminate remaining usages of the global system instance
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 11 | ||||
| -rw-r--r-- | src/core/core.cpp | 7 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 1 | ||||
| -rw-r--r-- | src/core/gdbstub/gdbstub.cpp | 1397 | ||||
| -rw-r--r-- | src/core/gdbstub/gdbstub.h | 114 | ||||
| -rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 3 | ||||
| -rw-r--r-- | src/core/loader/kip.cpp | 3 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 6 | ||||
| -rw-r--r-- | src/core/loader/nso.cpp | 5 | ||||
| -rw-r--r-- | src/core/settings.cpp | 17 | ||||
| -rw-r--r-- | src/core/settings.h | 8 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_dialog.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_per_game.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_profile_manager.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 12 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_ui.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 36 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 9 | ||||
| -rw-r--r-- | src/yuzu_tester/yuzu.cpp | 7 | 
21 files changed, 58 insertions, 1593 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e370fd225..66de33799 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -135,8 +135,6 @@ add_library(core STATIC      frontend/framebuffer_layout.cpp      frontend/framebuffer_layout.h      frontend/input.h -    gdbstub/gdbstub.cpp -    gdbstub/gdbstub.h      hardware_interrupt_manager.cpp      hardware_interrupt_manager.h      hle/ipc.h diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 9f170a224..5c2060d78 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -14,7 +14,6 @@  #include "core/arm/dynarmic/arm_exclusive_monitor.h"  #include "core/core.h"  #include "core/core_timing.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hardware_properties.h"  #include "core/hle/kernel/process.h"  #include "core/hle/kernel/scheduler.h" @@ -96,16 +95,6 @@ public:          case Dynarmic::A64::Exception::Yield:              return;          case Dynarmic::A64::Exception::Breakpoint: -            if (GDBStub::IsServerEnabled()) { -                parent.jit->HaltExecution(); -                parent.SetPC(pc); -                Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); -                parent.SaveContext(thread->GetContext64()); -                GDBStub::Break(); -                GDBStub::SendTrap(thread, 5); -                return; -            } -            [[fallthrough]];          default:              ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",                         static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); diff --git a/src/core/core.cpp b/src/core/core.cpp index 7ca3652af..f4bbc9ec3 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -25,7 +25,6 @@  #include "core/file_sys/sdmc_factory.h"  #include "core/file_sys/vfs_concat.h"  #include "core/file_sys/vfs_real.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hardware_interrupt_manager.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/kernel.h" @@ -186,11 +185,8 @@ struct System::Impl {          }          service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); -          services = std::make_unique<Service::Services>(service_manager, system); -        GDBStub::DeferStart(); - -        interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); +        interrupt_manager = std::make_unique<Hardware::InterruptManager>(system);          // Initialize time manager, which must happen after kernel is created          time_manager.Initialize(); @@ -297,7 +293,6 @@ struct System::Impl {          }          // Shutdown emulation session -        GDBStub::Shutdown();          services.reset();          service_manager.reset();          cheat_engine.reset(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 100e90d82..eeeb6e8df 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -10,7 +10,6 @@  #include "core/core.h"  #include "core/core_timing.h"  #include "core/cpu_manager.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/physical_core.h"  #include "core/hle/kernel/scheduler.h" diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp deleted file mode 100644 index 97ee65464..000000000 --- a/src/core/gdbstub/gdbstub.cpp +++ /dev/null @@ -1,1397 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. - -#include <algorithm> -#include <atomic> -#include <climits> -#include <csignal> -#include <cstdarg> -#include <cstdio> -#include <cstring> -#include <map> -#include <numeric> -#include <fcntl.h> - -#ifdef _WIN32 -#include <winsock2.h> -// winsock2.h needs to be included first to prevent winsock.h being included by other includes -#include <io.h> -#include <iphlpapi.h> -#include <ws2tcpip.h> -#define SHUT_RDWR 2 -#else -#include <netinet/in.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <unistd.h> -#endif - -#include "common/logging/log.h" -#include "common/string_util.h" -#include "common/swap.h" -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "core/gdbstub/gdbstub.h" -#include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/scheduler.h" -#include "core/loader/loader.h" -#include "core/memory.h" - -namespace GDBStub { -namespace { -constexpr int GDB_BUFFER_SIZE = 10000; - -constexpr char GDB_STUB_START = '$'; -constexpr char GDB_STUB_END = '#'; -constexpr char GDB_STUB_ACK = '+'; -constexpr char GDB_STUB_NACK = '-'; - -#ifndef SIGTRAP -constexpr u32 SIGTRAP = 5; -#endif - -#ifndef SIGTERM -constexpr u32 SIGTERM = 15; -#endif - -#ifndef MSG_WAITALL -constexpr u32 MSG_WAITALL = 8; -#endif - -constexpr u32 LR_REGISTER = 30; -constexpr u32 SP_REGISTER = 31; -constexpr u32 PC_REGISTER = 32; -constexpr u32 PSTATE_REGISTER = 33; -constexpr u32 UC_ARM64_REG_Q0 = 34; -constexpr u32 FPCR_REGISTER = 66; - -// For sample XML files see the GDB source /gdb/features -// GDB also wants the l character at the start -// This XML defines what the registers are for this specific ARM device -constexpr char target_xml[] = -    R"(l<?xml version="1.0"?> -<!DOCTYPE target SYSTEM "gdb-target.dtd"> -<target version="1.0"> -  <feature name="org.gnu.gdb.aarch64.core"> -    <reg name="x0" bitsize="64"/> -    <reg name="x1" bitsize="64"/> -    <reg name="x2" bitsize="64"/> -    <reg name="x3" bitsize="64"/> -    <reg name="x4" bitsize="64"/> -    <reg name="x5" bitsize="64"/> -    <reg name="x6" bitsize="64"/> -    <reg name="x7" bitsize="64"/> -    <reg name="x8" bitsize="64"/> -    <reg name="x9" bitsize="64"/> -    <reg name="x10" bitsize="64"/> -    <reg name="x11" bitsize="64"/> -    <reg name="x12" bitsize="64"/> -    <reg name="x13" bitsize="64"/> -    <reg name="x14" bitsize="64"/> -    <reg name="x15" bitsize="64"/> -    <reg name="x16" bitsize="64"/> -    <reg name="x17" bitsize="64"/> -    <reg name="x18" bitsize="64"/> -    <reg name="x19" bitsize="64"/> -    <reg name="x20" bitsize="64"/> -    <reg name="x21" bitsize="64"/> -    <reg name="x22" bitsize="64"/> -    <reg name="x23" bitsize="64"/> -    <reg name="x24" bitsize="64"/> -    <reg name="x25" bitsize="64"/> -    <reg name="x26" bitsize="64"/> -    <reg name="x27" bitsize="64"/> -    <reg name="x28" bitsize="64"/> -    <reg name="x29" bitsize="64"/> -    <reg name="x30" bitsize="64"/> -    <reg name="sp" bitsize="64" type="data_ptr"/> - -    <reg name="pc" bitsize="64" type="code_ptr"/> - -    <flags id="pstate_flags" size="4"> -      <field name="SP" start="0" end="0"/> -      <field name="" start="1" end="1"/> -      <field name="EL" start="2" end="3"/> -      <field name="nRW" start="4" end="4"/> -      <field name="" start="5" end="5"/> -      <field name="F" start="6" end="6"/> -      <field name="I" start="7" end="7"/> -      <field name="A" start="8" end="8"/> -      <field name="D" start="9" end="9"/> - -      <field name="IL" start="20" end="20"/> -      <field name="SS" start="21" end="21"/> - -      <field name="V" start="28" end="28"/> -      <field name="C" start="29" end="29"/> -      <field name="Z" start="30" end="30"/> -      <field name="N" start="31" end="31"/> -    </flags> -    <reg name="pstate" bitsize="32" type="pstate_flags"/> -  </feature> -  <feature name="org.gnu.gdb.aarch64.fpu"> -  </feature> -</target> -)"; - -int gdbserver_socket = -1; -bool defer_start = false; - -u8 command_buffer[GDB_BUFFER_SIZE]; -u32 command_length; - -u32 latest_signal = 0; -bool memory_break = false; - -Kernel::Thread* current_thread = nullptr; -u32 current_core = 0; - -// Binding to a port within the reserved ports range (0-1023) requires root permissions, -// so default to a port outside of that range. -u16 gdbstub_port = 24689; - -bool halt_loop = true; -bool step_loop = false; -bool send_trap = false; - -// If set to false, the server will never be started and no -// gdbstub-related functions will be executed. -std::atomic<bool> server_enabled(false); - -#ifdef _WIN32 -WSADATA InitData; -#endif - -struct Breakpoint { -    bool active; -    VAddr addr; -    u64 len; -    std::array<u8, 4> inst; -}; - -using BreakpointMap = std::map<VAddr, Breakpoint>; -BreakpointMap breakpoints_execute; -BreakpointMap breakpoints_read; -BreakpointMap breakpoints_write; - -struct Module { -    std::string name; -    VAddr beg; -    VAddr end; -}; - -std::vector<Module> modules; -} // Anonymous namespace - -void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) { -    Module module; -    if (add_elf_ext) { -        Common::SplitPath(name, nullptr, &module.name, nullptr); -        module.name += ".elf"; -    } else { -        module.name = std::move(name); -    } -    module.beg = beg; -    module.end = end; -    modules.push_back(std::move(module)); -} - -static Kernel::Thread* FindThreadById(s64 id) { -    const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); -    for (auto& thread : threads) { -        if (thread->GetThreadID() == static_cast<u64>(id)) { -            current_core = thread->GetProcessorID(); -            return thread.get(); -        } -    } -    return nullptr; -} - -static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) { -    if (!thread) { -        return 0; -    } - -    const auto& thread_context = thread->GetContext64(); - -    if (id < SP_REGISTER) { -        return thread_context.cpu_registers[id]; -    } else if (id == SP_REGISTER) { -        return thread_context.sp; -    } else if (id == PC_REGISTER) { -        return thread_context.pc; -    } else if (id == PSTATE_REGISTER) { -        return thread_context.pstate; -    } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { -        return thread_context.vector_registers[id - UC_ARM64_REG_Q0][0]; -    } else { -        return 0; -    } -} - -static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) { -    if (!thread) { -        return; -    } - -    auto& thread_context = thread->GetContext64(); - -    if (id < SP_REGISTER) { -        thread_context.cpu_registers[id] = val; -    } else if (id == SP_REGISTER) { -        thread_context.sp = val; -    } else if (id == PC_REGISTER) { -        thread_context.pc = val; -    } else if (id == PSTATE_REGISTER) { -        thread_context.pstate = static_cast<u32>(val); -    } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { -        thread_context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; -    } -} - -static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { -    if (!thread) { -        return u128{0}; -    } - -    auto& thread_context = thread->GetContext64(); - -    if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { -        return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; -    } else if (id == FPCR_REGISTER) { -        return u128{thread_context.fpcr, 0}; -    } else { -        return u128{0}; -    } -} - -static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) { -    if (!thread) { -        return; -    } - -    auto& thread_context = thread->GetContext64(); - -    if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { -        thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; -    } else if (id == FPCR_REGISTER) { -        thread_context.fpcr = static_cast<u32>(val[0]); -    } -} - -/** - * Turns hex string character into the equivalent byte. - * - * @param hex Input hex character to be turned into byte. - */ -static u8 HexCharToValue(u8 hex) { -    if (hex >= '0' && hex <= '9') { -        return static_cast<u8>(hex - '0'); -    } else if (hex >= 'a' && hex <= 'f') { -        return static_cast<u8>(hex - 'a' + 0xA); -    } else if (hex >= 'A' && hex <= 'F') { -        return static_cast<u8>(hex - 'A' + 0xA); -    } - -    LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); -    return 0; -} - -/** - * Turn nibble of byte into hex string character. - * - * @param n Nibble to be turned into hex character. - */ -static u8 NibbleToHex(u8 n) { -    n &= 0xF; -    if (n < 0xA) { -        return static_cast<u8>('0' + n); -    } else { -        return static_cast<u8>('a' + n - 0xA); -    } -} - -/** - * Converts input hex string characters into an array of equivalent of u8 bytes. - * - * @param src Pointer to array of output hex string characters. - * @param len Length of src array. - */ -static u32 HexToInt(const u8* src, std::size_t len) { -    u32 output = 0; -    while (len-- > 0) { -        output = (output << 4) | HexCharToValue(src[0]); -        src++; -    } -    return output; -} - -/** - * Converts input hex string characters into an array of equivalent of u8 bytes. - * - * @param src Pointer to array of output hex string characters. - * @param len Length of src array. - */ -static u64 HexToLong(const u8* src, std::size_t len) { -    u64 output = 0; -    while (len-- > 0) { -        output = (output << 4) | HexCharToValue(src[0]); -        src++; -    } -    return output; -} - -/** - * Converts input array of u8 bytes into their equivalent hex string characters. - * - * @param dest Pointer to buffer to store output hex string characters. - * @param src Pointer to array of u8 bytes. - * @param len Length of src array. - */ -static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) { -    while (len-- > 0) { -        const u8 tmp = *src++; -        *dest++ = NibbleToHex(static_cast<u8>(tmp >> 4)); -        *dest++ = NibbleToHex(tmp); -    } -} - -/** - * Converts input gdb-formatted hex string characters into an array of equivalent of u8 bytes. - * - * @param dest Pointer to buffer to store u8 bytes. - * @param src Pointer to array of output hex string characters. - * @param len Length of src array. - */ -static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) { -    while (len-- > 0) { -        *dest++ = static_cast<u8>((HexCharToValue(src[0]) << 4) | HexCharToValue(src[1])); -        src += 2; -    } -} - -/** - * Convert a u32 into a gdb-formatted hex string. - * - * @param dest Pointer to buffer to store output hex string characters. - * @param v    Value to convert. - */ -static void IntToGdbHex(u8* dest, u32 v) { -    for (int i = 0; i < 8; i += 2) { -        dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); -        dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1)))); -    } -} - -/** - * Convert a u64 into a gdb-formatted hex string. - * - * @param dest Pointer to buffer to store output hex string characters. - * @param v    Value to convert. - */ -static void LongToGdbHex(u8* dest, u64 v) { -    for (int i = 0; i < 16; i += 2) { -        dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); -        dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1)))); -    } -} - -/** - * Convert a gdb-formatted hex string into a u32. - * - * @param src Pointer to hex string. - */ -static u32 GdbHexToInt(const u8* src) { -    u32 output = 0; - -    for (int i = 0; i < 8; i += 2) { -        output = (output << 4) | HexCharToValue(src[7 - i - 1]); -        output = (output << 4) | HexCharToValue(src[7 - i]); -    } - -    return output; -} - -/** - * Convert a gdb-formatted hex string into a u64. - * - * @param src Pointer to hex string. - */ -static u64 GdbHexToLong(const u8* src) { -    u64 output = 0; - -    for (int i = 0; i < 16; i += 2) { -        output = (output << 4) | HexCharToValue(src[15 - i - 1]); -        output = (output << 4) | HexCharToValue(src[15 - i]); -    } - -    return output; -} - -/** - * Convert a gdb-formatted hex string into a u128. - * - * @param src Pointer to hex string. - */ -static u128 GdbHexToU128(const u8* src) { -    u128 output; - -    for (int i = 0; i < 16; i += 2) { -        output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]); -        output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]); -    } - -    for (int i = 0; i < 16; i += 2) { -        output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]); -        output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]); -    } - -    return output; -} - -/// Read a byte from the gdb client. -static u8 ReadByte() { -    u8 c; -    std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); -    if (received_size != 1) { -        LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); -        Shutdown(); -    } - -    return c; -} - -/// Calculate the checksum of the current command buffer. -static u8 CalculateChecksum(const u8* buffer, std::size_t length) { -    return static_cast<u8>(std::accumulate(buffer, buffer + length, u8{0}, -                                           [](u8 lhs, u8 rhs) { return u8(lhs + rhs); })); -} - -/** - * Get the map of breakpoints for a given breakpoint type. - * - * @param type Type of breakpoint map. - */ -static BreakpointMap& GetBreakpointMap(BreakpointType type) { -    switch (type) { -    case BreakpointType::Execute: -        return breakpoints_execute; -    case BreakpointType::Read: -        return breakpoints_read; -    case BreakpointType::Write: -        return breakpoints_write; -    default: -        return breakpoints_read; -    } -} - -/** - * Remove the breakpoint from the given address of the specified type. - * - * @param type Type of breakpoint. - * @param addr Address of breakpoint. - */ -static void RemoveBreakpoint(BreakpointType type, VAddr addr) { -    BreakpointMap& p = GetBreakpointMap(type); - -    const auto bp = p.find(addr); -    if (bp == p.end()) { -        return; -    } - -    LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", -              bp->second.len, bp->second.addr, static_cast<int>(type)); - -    if (type == BreakpointType::Execute) { -        auto& system = Core::System::GetInstance(); -        system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); -        system.InvalidateCpuInstructionCaches(); -    } -    p.erase(addr); -} - -BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) { -    const BreakpointMap& p = GetBreakpointMap(type); -    const auto next_breakpoint = p.lower_bound(addr); -    BreakpointAddress breakpoint; - -    if (next_breakpoint != p.end()) { -        breakpoint.address = next_breakpoint->first; -        breakpoint.type = type; -    } else { -        breakpoint.address = 0; -        breakpoint.type = BreakpointType::None; -    } - -    return breakpoint; -} - -bool CheckBreakpoint(VAddr addr, BreakpointType type) { -    if (!IsConnected()) { -        return false; -    } - -    const BreakpointMap& p = GetBreakpointMap(type); -    const auto bp = p.find(addr); - -    if (bp == p.end()) { -        return false; -    } - -    u64 len = bp->second.len; - -    // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints -    // no matter if it's a 4-byte or 2-byte instruction. When you execute a -    // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on -    // two instructions instead of the single instruction you placed the breakpoint -    // on. So, as a way to make sure that execution breakpoints are only breaking -    // on the instruction that was specified, set the length of an execution -    // breakpoint to 1. This should be fine since the CPU should never begin executing -    // an instruction anywhere except the beginning of the instruction. -    if (type == BreakpointType::Execute) { -        len = 1; -    } - -    if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { -        LOG_DEBUG(Debug_GDBStub, -                  "Found breakpoint type {} @ {:016X}, range: {:016X}" -                  " - {:016X} ({:X} bytes)", -                  static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len); -        return true; -    } - -    return false; -} - -/** - * Send packet to gdb client. - * - * @param packet Packet to be sent to client. - */ -static void SendPacket(const char packet) { -    std::size_t sent_size = send(gdbserver_socket, &packet, 1, 0); -    if (sent_size != 1) { -        LOG_ERROR(Debug_GDBStub, "send failed"); -    } -} - -/** - * Send reply to gdb client. - * - * @param reply Reply to be sent to client. - */ -static void SendReply(const char* reply) { -    if (!IsConnected()) { -        return; -    } - -    LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); - -    memset(command_buffer, 0, sizeof(command_buffer)); - -    command_length = static_cast<u32>(strlen(reply)); -    if (command_length + 4 > sizeof(command_buffer)) { -        LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); -        return; -    } - -    memcpy(command_buffer + 1, reply, command_length); - -    const u8 checksum = CalculateChecksum(command_buffer, command_length + 1); -    command_buffer[0] = GDB_STUB_START; -    command_buffer[command_length + 1] = GDB_STUB_END; -    command_buffer[command_length + 2] = NibbleToHex(static_cast<u8>(checksum >> 4)); -    command_buffer[command_length + 3] = NibbleToHex(checksum); - -    u8* ptr = command_buffer; -    u32 left = command_length + 4; -    while (left > 0) { -        const auto sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0); -        if (sent_size < 0) { -            LOG_ERROR(Debug_GDBStub, "gdb: send failed"); -            return Shutdown(); -        } - -        left -= static_cast<u32>(sent_size); -        ptr += sent_size; -    } -} - -/// Handle query command from gdb client. -static void HandleQuery() { -    LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); - -    const char* query = reinterpret_cast<const char*>(command_buffer + 1); - -    if (strcmp(query, "TStatus") == 0) { -        SendReply("T0"); -    } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { -        // PacketSize needs to be large enough for target xml -        std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; -        if (!modules.empty()) { -            buffer += ";qXfer:libraries:read+"; -        } -        SendReply(buffer.c_str()); -    } else if (strncmp(query, "Xfer:features:read:target.xml:", -                       strlen("Xfer:features:read:target.xml:")) == 0) { -        SendReply(target_xml); -    } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { -        const VAddr base_address = -            Core::System::GetInstance().CurrentProcess()->PageTable().GetCodeRegionStart(); -        std::string buffer = fmt::format("TextSeg={:0x}", base_address); -        SendReply(buffer.c_str()); -    } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { -        std::string val = "m"; -        const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); -        for (const auto& thread : threads) { -            val += fmt::format("{:x},", thread->GetThreadID()); -        } -        val.pop_back(); -        SendReply(val.c_str()); -    } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { -        SendReply("l"); -    } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { -        std::string buffer; -        buffer += "l<?xml version=\"1.0\"?>"; -        buffer += "<threads>"; -        const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); -        for (const auto& thread : threads) { -            buffer += -                fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*", -                            thread->GetThreadID(), thread->GetProcessorID(), thread->GetThreadID()); -        } -        buffer += "</threads>"; -        SendReply(buffer.c_str()); -    } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { -        std::string buffer; -        buffer += "l<?xml version=\"1.0\"?>"; -        buffer += "<library-list>"; -        for (const auto& module : modules) { -            buffer += -                fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*", -                            module.name, module.beg); -        } -        buffer += "</library-list>"; -        SendReply(buffer.c_str()); -    } else { -        SendReply(""); -    } -} - -/// Handle set thread command from gdb client. -static void HandleSetThread() { -    int thread_id = -1; -    if (command_buffer[2] != '-') { -        thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2)); -    } -    if (thread_id >= 1) { -        current_thread = FindThreadById(thread_id); -    } -    if (!current_thread) { -        thread_id = 1; -        current_thread = FindThreadById(thread_id); -    } -    if (current_thread) { -        SendReply("OK"); -        return; -    } -    SendReply("E01"); -} - -/// Handle thread alive command from gdb client. -static void HandleThreadAlive() { -    int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1)); -    if (thread_id == 0) { -        thread_id = 1; -    } -    if (FindThreadById(thread_id)) { -        SendReply("OK"); -        return; -    } -    SendReply("E01"); -} - -/** - * Send signal packet to client. - * - * @param signal Signal to be sent to client. - */ -static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { -    if (gdbserver_socket == -1) { -        return; -    } - -    latest_signal = signal; - -    if (!thread) { -        full = false; -    } - -    std::string buffer; -    if (full) { -        buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, -                             PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, -                             Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, -                             Common::swap64(RegRead(LR_REGISTER, thread))); -    } else { -        buffer = fmt::format("T{:02x}", latest_signal); -    } - -    if (thread) { -        buffer += fmt::format(";thread:{:x};", thread->GetThreadID()); -    } - -    SendReply(buffer.c_str()); -} - -/// Read command from gdb client. -static void ReadCommand() { -    command_length = 0; -    memset(command_buffer, 0, sizeof(command_buffer)); - -    u8 c = ReadByte(); -    if (c == '+') { -        // ignore ack -        return; -    } else if (c == 0x03) { -        LOG_INFO(Debug_GDBStub, "gdb: found break command"); -        halt_loop = true; -        SendSignal(current_thread, SIGTRAP); -        return; -    } else if (c != GDB_STUB_START) { -        LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); -        return; -    } - -    while ((c = ReadByte()) != GDB_STUB_END) { -        if (command_length >= sizeof(command_buffer)) { -            LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); -            SendPacket(GDB_STUB_NACK); -            return; -        } -        command_buffer[command_length++] = c; -    } - -    auto checksum_received = static_cast<u32>(HexCharToValue(ReadByte()) << 4); -    checksum_received |= static_cast<u32>(HexCharToValue(ReadByte())); - -    const u32 checksum_calculated = CalculateChecksum(command_buffer, command_length); - -    if (checksum_received != checksum_calculated) { -        LOG_ERROR(Debug_GDBStub, -                  "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", -                  checksum_calculated, checksum_received, command_buffer, command_length); - -        command_length = 0; - -        SendPacket(GDB_STUB_NACK); -        return; -    } - -    SendPacket(GDB_STUB_ACK); -} - -/// Check if there is data to be read from the gdb client. -static bool IsDataAvailable() { -    if (!IsConnected()) { -        return false; -    } - -    fd_set fd_socket; - -    FD_ZERO(&fd_socket); -    FD_SET(static_cast<u32>(gdbserver_socket), &fd_socket); - -    struct timeval t; -    t.tv_sec = 0; -    t.tv_usec = 0; - -    if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { -        LOG_ERROR(Debug_GDBStub, "select failed"); -        return false; -    } - -    return FD_ISSET(gdbserver_socket, &fd_socket) != 0; -} - -/// Send requested register to gdb client. -static void ReadRegister() { -    static u8 reply[64]; -    memset(reply, 0, sizeof(reply)); - -    u32 id = HexCharToValue(command_buffer[1]); -    if (command_buffer[2] != '\0') { -        id <<= 4; -        id |= HexCharToValue(command_buffer[2]); -    } - -    if (id <= SP_REGISTER) { -        LongToGdbHex(reply, RegRead(id, current_thread)); -    } else if (id == PC_REGISTER) { -        LongToGdbHex(reply, RegRead(id, current_thread)); -    } else if (id == PSTATE_REGISTER) { -        IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); -    } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { -        u128 r = FpuRead(id, current_thread); -        LongToGdbHex(reply, r[0]); -        LongToGdbHex(reply + 16, r[1]); -    } else if (id == FPCR_REGISTER) { -        u128 r = FpuRead(id, current_thread); -        IntToGdbHex(reply, static_cast<u32>(r[0])); -    } else if (id == FPCR_REGISTER + 1) { -        u128 r = FpuRead(id, current_thread); -        IntToGdbHex(reply, static_cast<u32>(r[0] >> 32)); -    } - -    SendReply(reinterpret_cast<char*>(reply)); -} - -/// Send all registers to the gdb client. -static void ReadRegisters() { -    static u8 buffer[GDB_BUFFER_SIZE - 4]; -    memset(buffer, 0, sizeof(buffer)); - -    u8* bufptr = buffer; - -    for (u32 reg = 0; reg <= SP_REGISTER; reg++) { -        LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); -    } - -    bufptr += 32 * 16; - -    LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); - -    bufptr += 16; - -    IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread))); - -    bufptr += 8; - -    u128 r; - -    for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) { -        r = FpuRead(reg, current_thread); -        LongToGdbHex(bufptr + reg * 32, r[0]); -        LongToGdbHex(bufptr + reg * 32 + 16, r[1]); -    } - -    bufptr += 32 * 32; - -    r = FpuRead(FPCR_REGISTER, current_thread); -    IntToGdbHex(bufptr, static_cast<u32>(r[0])); - -    bufptr += 8; - -    SendReply(reinterpret_cast<char*>(buffer)); -} - -/// Modify data of register specified by gdb client. -static void WriteRegister() { -    const u8* buffer_ptr = command_buffer + 3; - -    u32 id = HexCharToValue(command_buffer[1]); -    if (command_buffer[2] != '=') { -        ++buffer_ptr; -        id <<= 4; -        id |= HexCharToValue(command_buffer[2]); -    } - -    if (id <= SP_REGISTER) { -        RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); -    } else if (id == PC_REGISTER) { -        RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); -    } else if (id == PSTATE_REGISTER) { -        RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); -    } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { -        FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread); -    } else if (id == FPCR_REGISTER) { -    } else if (id == FPCR_REGISTER + 1) { -    } - -    // Update ARM context, skipping scheduler - no running threads at this point -    Core::System::GetInstance() -        .ArmInterface(current_core) -        .LoadContext(current_thread->GetContext64()); - -    SendReply("OK"); -} - -/// Modify all registers with data received from the client. -static void WriteRegisters() { -    const u8* buffer_ptr = command_buffer + 1; - -    if (command_buffer[0] != 'G') -        return SendReply("E01"); - -    for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) { -        if (reg <= SP_REGISTER) { -            RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); -        } else if (reg == PC_REGISTER) { -            RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); -        } else if (reg == PSTATE_REGISTER) { -            RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); -        } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { -            RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); -        } else if (reg == FPCR_REGISTER) { -            RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); -        } else if (reg == FPCR_REGISTER + 1) { -            RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); -        } -    } - -    // Update ARM context, skipping scheduler - no running threads at this point -    Core::System::GetInstance() -        .ArmInterface(current_core) -        .LoadContext(current_thread->GetContext64()); - -    SendReply("OK"); -} - -/// Read location in memory specified by gdb client. -static void ReadMemory() { -    static u8 reply[GDB_BUFFER_SIZE - 4]; - -    auto start_offset = command_buffer + 1; -    const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); - -    start_offset = addr_pos + 1; -    const u64 len = -        HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); - -    LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); - -    if (len * 2 > sizeof(reply)) { -        SendReply("E01"); -    } - -    auto& memory = Core::System::GetInstance().Memory(); -    if (!memory.IsValidVirtualAddress(addr)) { -        return SendReply("E00"); -    } - -    std::vector<u8> data(len); -    memory.ReadBlock(addr, data.data(), len); - -    MemToGdbHex(reply, data.data(), len); -    reply[len * 2] = '\0'; -    SendReply(reinterpret_cast<char*>(reply)); -} - -/// Modify location in memory with data received from the gdb client. -static void WriteMemory() { -    auto start_offset = command_buffer + 1; -    const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); - -    start_offset = addr_pos + 1; -    const auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); -    const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); - -    auto& system = Core::System::GetInstance(); -    auto& memory = system.Memory(); -    if (!memory.IsValidVirtualAddress(addr)) { -        return SendReply("E00"); -    } - -    std::vector<u8> data(len); -    GdbHexToMem(data.data(), len_pos + 1, len); -    memory.WriteBlock(addr, data.data(), len); -    system.InvalidateCpuInstructionCaches(); -    SendReply("OK"); -} - -void Break(bool is_memory_break) { -    send_trap = true; - -    memory_break = is_memory_break; -} - -/// Tell the CPU that it should perform a single step. -static void Step() { -    if (command_length > 1) { -        RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); -        // Update ARM context, skipping scheduler - no running threads at this point -        Core::System::GetInstance() -            .ArmInterface(current_core) -            .LoadContext(current_thread->GetContext64()); -    } -    step_loop = true; -    halt_loop = true; -    send_trap = true; -    Core::System::GetInstance().InvalidateCpuInstructionCaches(); -} - -/// Tell the CPU if we hit a memory breakpoint. -bool IsMemoryBreak() { -    if (!IsConnected()) { -        return false; -    } - -    return memory_break; -} - -/// Tell the CPU to continue executing. -static void Continue() { -    memory_break = false; -    step_loop = false; -    halt_loop = false; -    Core::System::GetInstance().InvalidateCpuInstructionCaches(); -} - -/** - * Commit breakpoint to list of breakpoints. - * - * @param type Type of breakpoint. - * @param addr Address of breakpoint. - * @param len Length of breakpoint. - */ -static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { -    BreakpointMap& p = GetBreakpointMap(type); - -    Breakpoint breakpoint; -    breakpoint.active = true; -    breakpoint.addr = addr; -    breakpoint.len = len; - -    auto& system = Core::System::GetInstance(); -    auto& memory = system.Memory(); -    memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); - -    static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; -    if (type == BreakpointType::Execute) { -        memory.WriteBlock(addr, btrap.data(), btrap.size()); -        system.InvalidateCpuInstructionCaches(); -    } -    p.insert({addr, breakpoint}); - -    LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", -              static_cast<int>(type), breakpoint.len, breakpoint.addr); - -    return true; -} - -/// Handle add breakpoint command from gdb client. -static void AddBreakpoint() { -    BreakpointType type; - -    u8 type_id = HexCharToValue(command_buffer[1]); -    switch (type_id) { -    case 0: -    case 1: -        type = BreakpointType::Execute; -        break; -    case 2: -        type = BreakpointType::Write; -        break; -    case 3: -        type = BreakpointType::Read; -        break; -    case 4: -        type = BreakpointType::Access; -        break; -    default: -        return SendReply("E01"); -    } - -    auto start_offset = command_buffer + 3; -    auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); - -    start_offset = addr_pos + 1; -    u64 len = -        HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); - -    if (type == BreakpointType::Access) { -        // Access is made up of Read and Write types, so add both breakpoints -        type = BreakpointType::Read; - -        if (!CommitBreakpoint(type, addr, len)) { -            return SendReply("E02"); -        } - -        type = BreakpointType::Write; -    } - -    if (!CommitBreakpoint(type, addr, len)) { -        return SendReply("E02"); -    } - -    SendReply("OK"); -} - -/// Handle remove breakpoint command from gdb client. -static void RemoveBreakpoint() { -    BreakpointType type; - -    u8 type_id = HexCharToValue(command_buffer[1]); -    switch (type_id) { -    case 0: -    case 1: -        type = BreakpointType::Execute; -        break; -    case 2: -        type = BreakpointType::Write; -        break; -    case 3: -        type = BreakpointType::Read; -        break; -    case 4: -        type = BreakpointType::Access; -        break; -    default: -        return SendReply("E01"); -    } - -    auto start_offset = command_buffer + 3; -    auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); -    VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); - -    if (type == BreakpointType::Access) { -        // Access is made up of Read and Write types, so add both breakpoints -        type = BreakpointType::Read; -        RemoveBreakpoint(type, addr); - -        type = BreakpointType::Write; -    } - -    RemoveBreakpoint(type, addr); -    SendReply("OK"); -} - -void HandlePacket() { -    if (!IsConnected()) { -        if (defer_start) { -            ToggleServer(true); -        } -        return; -    } - -    if (!IsDataAvailable()) { -        return; -    } - -    ReadCommand(); -    if (command_length == 0) { -        return; -    } - -    LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); - -    switch (command_buffer[0]) { -    case 'q': -        HandleQuery(); -        break; -    case 'H': -        HandleSetThread(); -        break; -    case '?': -        SendSignal(current_thread, latest_signal); -        break; -    case 'k': -        Shutdown(); -        LOG_INFO(Debug_GDBStub, "killed by gdb"); -        return; -    case 'g': -        ReadRegisters(); -        break; -    case 'G': -        WriteRegisters(); -        break; -    case 'p': -        ReadRegister(); -        break; -    case 'P': -        WriteRegister(); -        break; -    case 'm': -        ReadMemory(); -        break; -    case 'M': -        WriteMemory(); -        break; -    case 's': -        Step(); -        return; -    case 'C': -    case 'c': -        Continue(); -        return; -    case 'z': -        RemoveBreakpoint(); -        break; -    case 'Z': -        AddBreakpoint(); -        break; -    case 'T': -        HandleThreadAlive(); -        break; -    default: -        SendReply(""); -        break; -    } -} - -void SetServerPort(u16 port) { -    gdbstub_port = port; -} - -void ToggleServer(bool status) { -    if (status) { -        server_enabled = status; - -        // Start server -        if (!IsConnected() && Core::System::GetInstance().IsPoweredOn()) { -            Init(); -        } -    } else { -        // Stop server -        if (IsConnected()) { -            Shutdown(); -        } - -        server_enabled = status; -    } -} - -void DeferStart() { -    defer_start = true; -} - -static void Init(u16 port) { -    if (!server_enabled) { -        // Set the halt loop to false in case the user enabled the gdbstub mid-execution. -        // This way the CPU can still execute normally. -        halt_loop = false; -        step_loop = false; -        return; -    } - -    // Setup initial gdbstub status -    halt_loop = true; -    step_loop = false; - -    breakpoints_execute.clear(); -    breakpoints_read.clear(); -    breakpoints_write.clear(); - -    modules.clear(); - -    // Start gdb server -    LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); - -    sockaddr_in saddr_server = {}; -    saddr_server.sin_family = AF_INET; -    saddr_server.sin_port = htons(port); -    saddr_server.sin_addr.s_addr = INADDR_ANY; - -#ifdef _WIN32 -    WSAStartup(MAKEWORD(2, 2), &InitData); -#endif - -    int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0)); -    if (tmpsock == -1) { -        LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); -    } - -    // Set socket to SO_REUSEADDR so it can always bind on the same port -    int reuse_enabled = 1; -    if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, -                   sizeof(reuse_enabled)) < 0) { -        LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); -    } - -    const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server); -    socklen_t server_addrlen = sizeof(saddr_server); -    if (bind(tmpsock, server_addr, server_addrlen) < 0) { -        LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); -    } - -    if (listen(tmpsock, 1) < 0) { -        LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); -    } - -    // Wait for gdb to connect -    LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); -    sockaddr_in saddr_client; -    sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client); -    socklen_t client_addrlen = sizeof(saddr_client); -    gdbserver_socket = static_cast<int>(accept(tmpsock, client_addr, &client_addrlen)); -    if (gdbserver_socket < 0) { -        // In the case that we couldn't start the server for whatever reason, just start CPU -        // execution like normal. -        halt_loop = false; -        step_loop = false; - -        LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); -    } else { -        LOG_INFO(Debug_GDBStub, "Client connected."); -        saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); -    } - -    // Clean up temporary socket if it's still alive at this point. -    if (tmpsock != -1) { -        shutdown(tmpsock, SHUT_RDWR); -    } -} - -void Init() { -    Init(gdbstub_port); -} - -void Shutdown() { -    if (!server_enabled) { -        return; -    } -    defer_start = false; - -    LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); -    if (gdbserver_socket != -1) { -        shutdown(gdbserver_socket, SHUT_RDWR); -        gdbserver_socket = -1; -    } - -#ifdef _WIN32 -    WSACleanup(); -#endif - -    LOG_INFO(Debug_GDBStub, "GDB stopped."); -} - -bool IsServerEnabled() { -    return server_enabled; -} - -bool IsConnected() { -    return IsServerEnabled() && gdbserver_socket != -1; -} - -bool GetCpuHaltFlag() { -    return halt_loop; -} - -bool GetCpuStepFlag() { -    return step_loop; -} - -void SetCpuStepFlag(bool is_step) { -    step_loop = is_step; -} - -void SendTrap(Kernel::Thread* thread, int trap) { -    if (!send_trap) { -        return; -    } - -    current_thread = thread; -    SendSignal(thread, trap); - -    halt_loop = true; -    send_trap = false; -} -}; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h deleted file mode 100644 index 8fe3c320b..000000000 --- a/src/core/gdbstub/gdbstub.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. - -#pragma once - -#include <string> -#include "common/common_types.h" -#include "core/hle/kernel/thread.h" - -namespace GDBStub { - -/// Breakpoint Method -enum class BreakpointType { -    None,    ///< None -    Execute, ///< Execution Breakpoint -    Read,    ///< Read Breakpoint -    Write,   ///< Write Breakpoint -    Access   ///< Access (R/W) Breakpoint -}; - -struct BreakpointAddress { -    VAddr address; -    BreakpointType type; -}; - -/** - * Set the port the gdbstub should use to listen for connections. - * - * @param port Port to listen for connection - */ -void SetServerPort(u16 port); - -/** - * Starts or stops the server if possible. - * - * @param status Set the server to enabled or disabled. - */ -void ToggleServer(bool status); - -/// Start the gdbstub server. -void Init(); - -/** - * Defer initialization of the gdbstub to the first packet processing functions. - * This avoids a case where the gdbstub thread is frozen after initialization - * and fails to respond in time to packets. - */ -void DeferStart(); - -/// Stop gdbstub server. -void Shutdown(); - -/// Checks if the gdbstub server is enabled. -bool IsServerEnabled(); - -/// Returns true if there is an active socket connection. -bool IsConnected(); - -/// Register module. -void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext = true); - -/** - * Signal to the gdbstub server that it should halt CPU execution. - * - * @param is_memory_break If true, the break resulted from a memory breakpoint. - */ -void Break(bool is_memory_break = false); - -/// Determine if there was a memory breakpoint. -bool IsMemoryBreak(); - -/// Read and handle packet from gdb client. -void HandlePacket(); - -/** - * Get the nearest breakpoint of the specified type at the given address. - * - * @param addr Address to search from. - * @param type Type of breakpoint. - */ -BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type); - -/** - * Check if a breakpoint of the specified type exists at the given address. - * - * @param addr Address of breakpoint. - * @param type Type of breakpoint. - */ -bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type); - -/// If set to true, the CPU will halt at the beginning of the next CPU loop. -bool GetCpuHaltFlag(); - -/// If set to true and the CPU is halted, the CPU will step one instruction. -bool GetCpuStepFlag(); - -/** - * When set to true, the CPU will step one instruction when the CPU is halted next. - * - * @param is_step - */ -void SetCpuStepFlag(bool is_step); - -/** - * Send trap signal from thread back to the gdbstub server. - * - * @param thread Sending thread. - * @param trap Trap no. - */ -void SendTrap(Kernel::Thread* thread, int trap); -} // namespace GDBStub diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 2002dc4f2..79ebf11de 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -12,7 +12,6 @@  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/patch_manager.h"  #include "core/file_sys/romfs_factory.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/memory/page_table.h"  #include "core/hle/kernel/process.h" @@ -180,8 +179,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect          next_load_addr = *tentative_next_load_addr;          modules.insert_or_assign(load_addr, module);          LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); -        // Register module with GDBStub -        GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);      }      // Find the RomFS by searching for a ".romfs" file in this directory diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 2a905d3e4..e162c4ff0 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -5,7 +5,6 @@  #include <cstring>  #include "core/file_sys/kernel_executable.h"  #include "core/file_sys/program_metadata.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/code_set.h"  #include "core/hle/kernel/memory/page_table.h"  #include "core/hle/kernel/process.h" @@ -91,8 +90,6 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,      program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());      codeset.DataSegment().size += kip->GetBSSSize(); -    GDBStub::RegisterModule(kip->GetName(), base_address, base_address + program_image.size()); -      codeset.memory = std::move(program_image);      process.LoadModule(std::move(codeset), base_address); diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 5f4b3104b..ccf8cc153 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -14,10 +14,10 @@  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/romfs_factory.h"  #include "core/file_sys/vfs_offset.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/code_set.h"  #include "core/hle/kernel/memory/page_table.h"  #include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/loader/nro.h"  #include "core/loader/nso.h" @@ -197,10 +197,6 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,      codeset.memory = std::move(program_image);      process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); -    // Register module with GDBStub -    GDBStub::RegisterModule(name, process.PageTable().GetCodeRegionStart(), -                            process.PageTable().GetCodeRegionEnd()); -      return true;  } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index aa85c1a29..95b6f339a 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -14,10 +14,10 @@  #include "common/swap.h"  #include "core/core.h"  #include "core/file_sys/patch_manager.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/code_set.h"  #include "core/hle/kernel/memory/page_table.h"  #include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h"  #include "core/loader/nso.h"  #include "core/memory.h"  #include "core/settings.h" @@ -159,9 +159,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S      codeset.memory = std::move(program_image);      process.LoadModule(std::move(codeset), load_base); -    // Register module with GDBStub -    GDBStub::RegisterModule(file.GetName(), load_base, load_base); -      return load_base + image_size;  } diff --git a/src/core/settings.cpp b/src/core/settings.cpp index aadbc3932..e9997a263 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -4,9 +4,10 @@  #include <string_view> +#include "common/assert.h"  #include "common/file_util.h" +#include "common/logging/log.h"  #include "core/core.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/service/hid/hid.h"  #include "core/settings.h"  #include "video_core/renderer_base.h" @@ -31,13 +32,9 @@ std::string GetTimeZoneString() {      return timezones[time_zone_index];  } -void Apply() { -    GDBStub::SetServerPort(values.gdbstub_port); -    GDBStub::ToggleServer(values.use_gdbstub); - -    auto& system_instance = Core::System::GetInstance(); -    if (system_instance.IsPoweredOn()) { -        system_instance.Renderer().RefreshBaseSettings(); +void Apply(Core::System& system) { +    if (system.IsPoweredOn()) { +        system.Renderer().RefreshBaseSettings();      }      Service::HID::ReloadInputDevices(); @@ -106,9 +103,9 @@ float Volume() {      return values.volume.GetValue();  } -void RestoreGlobalState() { +void RestoreGlobalState(bool is_powered_on) {      // If a game is running, DO NOT restore the global settings state -    if (Core::System::GetInstance().IsPoweredOn()) { +    if (is_powered_on) {          return;      } diff --git a/src/core/settings.h b/src/core/settings.h index 1143aba5d..3df611d5b 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -14,6 +14,10 @@  #include "common/common_types.h"  #include "input_common/settings.h" +namespace Core { +class System; +} +  namespace Settings {  enum class RendererBackend { @@ -247,11 +251,11 @@ float Volume();  std::string GetTimeZoneString(); -void Apply(); +void Apply(Core::System& system);  void LogSettings();  // Restore the global state of all applicable settings in the Values struct -void RestoreGlobalState(); +void RestoreGlobalState(bool is_powered_on);  // Fixes settings that are known to cause issues with the emulator  void Sanitize(); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 3c423a271..8be9e93c3 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -7,6 +7,7 @@  #include <QSettings>  #include "common/common_paths.h"  #include "common/file_util.h" +#include "core/core.h"  #include "core/hle/service/acc/profile_manager.h"  #include "core/hle/service/hid/controllers/npad.h"  #include "input_common/main.h" @@ -1598,7 +1599,7 @@ void Config::Reload() {      Settings::Sanitize();      // To apply default value changes      SaveValues(); -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());  }  void Config::Save() { diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 5041e0bf8..b33f8437a 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -5,6 +5,7 @@  #include <QHash>  #include <QListWidgetItem>  #include <QSignalBlocker> +#include "core/core.h"  #include "core/settings.h"  #include "ui_configure.h"  #include "yuzu/configuration/config.h" @@ -54,7 +55,7 @@ void ConfigureDialog::ApplyConfiguration() {      ui->debugTab->ApplyConfiguration();      ui->webTab->ApplyConfiguration();      ui->serviceTab->ApplyConfiguration(); -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());      Settings::LogSettings();  } diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 8eac3bd9d..f598513df 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -57,7 +57,7 @@ void ConfigurePerGame::ApplyConfiguration() {      ui->graphicsAdvancedTab->ApplyConfiguration();      ui->audioTab->ApplyConfiguration(); -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());      Settings::LogSettings();      game_config->Save(); diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 6334c4c50..13d9a4757 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp @@ -180,7 +180,7 @@ void ConfigureProfileManager::ApplyConfiguration() {          return;      } -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());  }  void ConfigureProfileManager::SelectUser(const QModelIndex& index) { diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 59a58d92c..6cf2032da 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -105,16 +105,18 @@ void ConfigureSystem::SetConfiguration() {  void ConfigureSystem::ReadSystemSettings() {}  void ConfigureSystem::ApplyConfiguration() { -    // Allow setting custom RTC even if system is powered on, to allow in-game time to be fast -    // forwared +    auto& system = Core::System::GetInstance(); + +    // Allow setting custom RTC even if system is powered on, +    // to allow in-game time to be fast forwarded      if (Settings::values.custom_rtc.UsingGlobal()) {          if (ui->custom_rtc_checkbox->isChecked()) {              Settings::values.custom_rtc.SetValue(                  std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch())); -            if (Core::System::GetInstance().IsPoweredOn()) { +            if (system.IsPoweredOn()) {                  const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() +                                       Service::Time::TimeManager::GetExternalTimeZoneOffset()}; -                Core::System::GetInstance().GetTimeManager().UpdateLocalSystemClockTime(posix_time); +                system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);              }          } else {              Settings::values.custom_rtc.SetValue(std::nullopt); @@ -197,7 +199,7 @@ void ConfigureSystem::ApplyConfiguration() {          }      } -    Settings::Apply(); +    Settings::Apply(system);  }  void ConfigureSystem::RefreshConsoleID() { diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index dbe3f78c8..aed876008 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -9,6 +9,7 @@  #include <QDirIterator>  #include "common/common_types.h"  #include "common/file_util.h" +#include "core/core.h"  #include "core/settings.h"  #include "ui_configure_ui.h"  #include "yuzu/configuration/configure_ui.h" @@ -84,7 +85,7 @@ void ConfigureUi::ApplyConfiguration() {      UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();      Common::FS::GetUserPath(Common::FS::UserPath::ScreenshotsDir,                              ui->screenshot_path_edit->text().toStdString()); -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());  }  void ConfigureUi::RequestGameListUpdate() { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 07fa85741..871ff4ae4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -172,7 +172,7 @@ void GMainWindow::ShowTelemetryCallout() {             "<br/><br/>Would you like to share your usage data with us?");      if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {          Settings::values.enable_telemetry = false; -        Settings::Apply(); +        Settings::Apply(Core::System::GetInstance());      }  } @@ -302,7 +302,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(      emit ControllerSelectorReconfigureFinished();      // Don't forget to apply settings. -    Settings::Apply(); +    Settings::Apply(Core::System::GetInstance());      config->Save();      UpdateStatusButtons(); @@ -571,11 +571,11 @@ void GMainWindow::InitializeWidgets() {          if (emulation_running) {              return;          } -        bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() || -                        Settings::values.use_multi_core.GetValue(); +        const bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() || +                              Settings::values.use_multi_core.GetValue();          Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);          async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); -        Settings::Apply(); +        Settings::Apply(Core::System::GetInstance());      });      async_status_button->setText(tr("ASYNC"));      async_status_button->setCheckable(true); @@ -590,12 +590,12 @@ void GMainWindow::InitializeWidgets() {              return;          }          Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue()); -        bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() || -                        Settings::values.use_multi_core.GetValue(); +        const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() || +                              Settings::values.use_multi_core.GetValue();          Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);          async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());          multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); -        Settings::Apply(); +        Settings::Apply(Core::System::GetInstance());      });      multicore_status_button->setText(tr("MULTICORE"));      multicore_status_button->setCheckable(true); @@ -630,7 +630,7 @@ void GMainWindow::InitializeWidgets() {              Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);          } -        Settings::Apply(); +        Settings::Apply(Core::System::GetInstance());      });  #endif // HAS_VULKAN      statusBar()->insertPermanentWidget(0, renderer_status_button); @@ -2130,14 +2130,14 @@ void GMainWindow::OnPauseGame() {  }  void GMainWindow::OnStopGame() { -    Core::System& system{Core::System::GetInstance()}; +    auto& system{Core::System::GetInstance()};      if (system.GetExitLock() && !ConfirmForceLockedExit()) {          return;      }      ShutdownGame(); -    Settings::RestoreGlobalState(); +    Settings::RestoreGlobalState(system.IsPoweredOn());      UpdateStatusButtons();  } @@ -2312,10 +2312,11 @@ void GMainWindow::OnConfigurePerGame() {  void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) {      const auto v_file = Core::GetGameFileFromPath(vfs, file_name); +    const auto& system = Core::System::GetInstance();      ConfigurePerGame dialog(this, title_id);      dialog.LoadFromFile(v_file); -    auto result = dialog.exec(); +    const auto result = dialog.exec();      if (result == QDialog::Accepted) {          dialog.ApplyConfiguration(); @@ -2325,13 +2326,14 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file          }          // Do not cause the global config to write local settings into the config file -        Settings::RestoreGlobalState(); +        const bool is_powered_on = system.IsPoweredOn(); +        Settings::RestoreGlobalState(is_powered_on); -        if (!Core::System::GetInstance().IsPoweredOn()) { +        if (!is_powered_on) {              config->Save();          }      } else { -        Settings::RestoreGlobalState(); +        Settings::RestoreGlobalState(system.IsPoweredOn());      }  } @@ -2602,7 +2604,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det          if (emu_thread) {              ShutdownGame(); -            Settings::RestoreGlobalState(); +            Settings::RestoreGlobalState(Core::System::GetInstance().IsPoweredOn());              UpdateStatusButtons();          }      } else { @@ -2774,7 +2776,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {      if (emu_thread != nullptr) {          ShutdownGame(); -        Settings::RestoreGlobalState(); +        Settings::RestoreGlobalState(Core::System::GetInstance().IsPoweredOn());          UpdateStatusButtons();      } diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index ba6e89249..c2efe1ee6 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -25,7 +25,6 @@  #include "core/crypto/key_manager.h"  #include "core/file_sys/registered_cache.h"  #include "core/file_sys/vfs_real.h" -#include "core/gdbstub/gdbstub.h"  #include "core/hle/kernel/process.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/loader/loader.h" @@ -174,13 +173,13 @@ int main(int argc, char** argv) {          return -1;      } +    auto& system{Core::System::GetInstance()}; +    InputCommon::InputSubsystem input_subsystem; +      // Apply the command line arguments      Settings::values.gdbstub_port = gdb_port;      Settings::values.use_gdbstub = use_gdbstub; -    Settings::Apply(); - -    Core::System& system{Core::System::GetInstance()}; -    InputCommon::InputSubsystem input_subsystem; +    Settings::Apply(system);      std::unique_ptr<EmuWindow_SDL2> emu_window;      switch (Settings::values.renderer_backend.GetValue()) { diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp index ea94a6537..50bd7ae41 100644 --- a/src/yuzu_tester/yuzu.cpp +++ b/src/yuzu_tester/yuzu.cpp @@ -160,10 +160,12 @@ int main(int argc, char** argv) {          return -1;      } +    Core::System& system{Core::System::GetInstance()}; +      Settings::values.use_gdbstub = false; -    Settings::Apply(); +    Settings::Apply(system); -    std::unique_ptr<EmuWindow_SDL2_Hide> emu_window{std::make_unique<EmuWindow_SDL2_Hide>()}; +    const auto emu_window{std::make_unique<EmuWindow_SDL2_Hide>()};      bool finished = false;      int return_value = 0; @@ -212,7 +214,6 @@ int main(int argc, char** argv) {              return_value = -1;      }; -    Core::System& system{Core::System::GetInstance()};      system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());      system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());      system.GetFileSystemController().CreateFactories(*system.GetFilesystem());  | 
