code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "MorpheusEnabler.hpp"
#include <Utils/Kdlsym.hpp>
#include <Utils/Logger.hpp>

#include <Mira.hpp>
#include <OrbisOS/Utilities.hpp>

extern "C"
{
	#include <sys/mman.h>
    #include <sys/eventhandler.h>
};

using namespace Mira::Plugins;
using namespace Mira::OrbisOS;

MorpheusEnabler::MorpheusEnabler() :
	m_processStartEvent(nullptr),
	m_resumeEvent(nullptr)
{

}

MorpheusEnabler::~MorpheusEnabler()
{

}

void MorpheusEnabler::ProcessStartEvent(void *arg, struct ::proc *p)
{
    auto strncmp = (int(*)(const char *, const char *, size_t))kdlsym(strncmp);

    if (!p)
        return;

    char* s_TitleId = (char*)((uint64_t)p + 0x390);
    if (strncmp(s_TitleId, "NPXS20000", 9) == 0)
        DoPatch();

    return;
}

void MorpheusEnabler::ResumeEvent()
{
    DoPatch();
    WriteLog(LL_Debug, "InstallEventHandlers finished");
    return;
}

bool MorpheusEnabler::DoPatch()
{
	WriteLog(LL_Debug, "patching SceShellCore");

	struct ::proc* s_Process = Utilities::FindProcessByName("SceShellCore");
	if (s_Process == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellCore");
		return false;
	}

	ProcVmMapEntry* s_Entries = nullptr;
	size_t s_NumEntries = 0;
	auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
	if (s_Ret < 0)
	{
		WriteLog(LL_Error, "could not get vm map");
		return false;
	}

	if (s_Entries == nullptr || s_NumEntries == 0)
	{
		WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
		return false;
	}

	uint8_t* s_TextStart = nullptr;
	for (auto i = 0; i < s_NumEntries; ++i)
	{
		if (s_Entries[i].prot == (PROT_READ | PROT_EXEC))
		{
			s_TextStart = (uint8_t*)s_Entries[i].start;
			break;
		}
	}

	if (s_TextStart == nullptr)
	{
		WriteLog(LL_Error, "could not find SceShellCore text start");
		return false;
	}

	WriteLog(LL_Debug, "SceShellCore .text: (%p)", s_TextStart);

	// Free the entries we got returned
	delete [] s_Entries;
	s_Entries = nullptr;

	s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_TextStart + ssc_enable_vr_patch), 3, (void*)"\x31\xC0\xC3", nullptr, true);
	if (s_Ret < 0)
	{
			WriteLog(LL_Error, "ssc_enable_vr");
			return false;
	}

	return true;
}

bool MorpheusEnabler::OnLoad()
{
	auto s_MainThread = Mira::Framework::GetFramework()->GetMainThread();
    if (s_MainThread == nullptr)
    {
        WriteLog(LL_Error, "could not get main mira thread");
        return false;
    }

    // Initialize the event handlers
    auto eventhandler_register = (eventhandler_tag(*)(struct eventhandler_list *list, const char *name, void *func, void *arg, int priority))kdlsym(eventhandler_register);

    m_processStartEvent = eventhandler_register(NULL, "process_exec_end", reinterpret_cast<void*>(MorpheusEnabler::ProcessStartEvent), NULL, EVENTHANDLER_PRI_LAST);
    m_resumeEvent = eventhandler_register(NULL, "system_resume_phase4", reinterpret_cast<void*>(MorpheusEnabler::ResumeEvent), NULL, EVENTHANDLER_PRI_LAST);

	return DoPatch();
}

bool MorpheusEnabler::OnUnload()
{
    auto eventhandler_deregister = (void(*)(struct eventhandler_list* a, struct eventhandler_entry* b))kdlsym(eventhandler_deregister);
    auto eventhandler_find_list = (struct eventhandler_list * (*)(const char *name))kdlsym(eventhandler_find_list);

    if (m_processStartEvent) {
        EVENTHANDLER_DEREGISTER(process_exec_end, m_processStartEvent);
        m_processStartEvent = nullptr;
    }

    if (m_resumeEvent) {
        EVENTHANDLER_DEREGISTER(process_exit, m_resumeEvent);
        m_resumeEvent = nullptr;
    }

	return true;
}

bool MorpheusEnabler::OnSuspend()
{
	return true;
}

bool MorpheusEnabler::OnResume()
{
	return true;
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Types.hpp>

extern "C"
{
    #include <sys/eventhandler.h>
};

namespace Mira
{
		namespace Plugins
		{
				class MorpheusEnabler : public Mira::Utils::IModule
				{
				private:
			            eventhandler_entry* m_processStartEvent;
			            eventhandler_entry* m_resumeEvent;
			    private:
			    		static bool DoPatch();
				public:
						MorpheusEnabler();
						virtual ~MorpheusEnabler();

						virtual const char* GetName() override { return "MorpheusEnabler"; }
						virtual bool OnLoad() override;
						virtual bool OnUnload() override;
						virtual bool OnSuspend() override;
						virtual bool OnResume() override;
				protected:
						static void ProcessStartEvent(void *arg, struct ::proc *p);
						static void ResumeEvent();
				};
		}
}

repo_name: veiledmerc/mira

license: mit


code:
#include "PS4GDB.hpp"
#include "kdl.h"
#include "log.h"
#include "gdbstub.hpp"
#include "syscalls.hpp"
#include <Utils/Kdlsym.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Hook.hpp>

#include <Utils/SysWrappers.hpp>

#include <sys/param.h>
#include <sys/types.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/stdint.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/unistd.h>
#include <vm/vm.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/sx.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/sysent.h>

#include <Mira.hpp>
#include <Utils/Kdlsym.hpp>

using namespace Mira::Plugins;

PS4GDB::PS4GDB()
{

}

PS4GDB::~PS4GDB()
{

}

bool PS4GDB::OnLoad()
{
    return this->SpawnKproc();
}

bool PS4GDB::OnUnload()
{
    return true;
}

bool PS4GDB::OnSuspend()
{
    return OnUnload();
}

bool PS4GDB::OnResume()
{
    return this->SpawnKproc();
}

void PS4GDB::GetRoot()
{
    struct prison **prison0 = NULL;
    struct vnode **rootvnode = NULL;
    struct thread *td = curthread;

	/* Resolve credentials */
	struct ucred *cred;
	struct filedesc *fd;

	fd = td->td_proc->p_fd;
	cred = td->td_proc->p_ucred;

	/* Escalate process to uid0 */
	cred->cr_uid = 0;
	cred->cr_ruid = 0;
	cred->cr_rgid = 0;
	cred->cr_groups[0] = 0;

	/* Break out of FreeBSD jail */
	prison0 = (struct prison **)kdlsym(prison0);
	cred->cr_prison = prison0[0];

	/* Set sony auth ID flag */
	cred->cr_sceAuthID = 0x3800000000000007ULL;

	/* Obtain system credentials for Sony stuff */
	cred->cr_sceCaps[0] = 0xffffffffffffffff;
	cred->cr_sceCaps[1] = 0xffffffffffffffff;

	/* Set vnode to real root "/" to defeat sandbox */
	rootvnode = (struct vnode **)kdlsym(rootvnode);
	fd->fd_rdir = rootvnode[0];
	fd->fd_jdir = rootvnode[0];
}

bool PS4GDB::SpawnKproc()
{
    auto kproc_create = (int(*)(void (*func)(void *), void *arg, struct proc **newpp, int flags, int pages, const char *fmt, ...)) kdlsym(kproc_create);
    auto kmalloc = (void*(*)(size_t size, struct	malloc_type *type, int Flags))kdlsym(malloc);
    auto kM_TEMP = (struct	malloc_type *)kdlsym(M_TEMP);

    struct proc *p = (struct proc*)kmalloc(sizeof(struct proc), kM_TEMP, 0x102);
    WriteLog(LL_Info, "PS4GDBMain allocated at: 0x%llx", (uint64_t)p);
    WriteLog(LL_Info, "Spawing KprocMain...");
    kproc_create(PS4GDB::PS4GDBMain, NULL, &p, 0, 0, "PS4GDB");
    return true;
}

void PS4GDB::PS4GDBMain(void *)
{
	WriteLog(LL_Info, "PS4GDB::PS4GDBMain Getting root...");
    PS4GDB::GetRoot();

    // create new vmspace
    WriteLog(LL_Info, "PS4GDB::PS4GDBMain Creating new vmspace...");
	vm_offset_t sv_minuser;
	struct vmspace *vmspace;
	struct proc *p = curproc;
	struct sysentvec *sv = (struct sysentvec *)kdlsym(self_orbis_sysvec);

    // allocate user mode virtual space
    auto kvmspace_alloc = (struct vmspace*(*)(vm_offset_t min, vm_offset_t max)) kdlsym(vmspace_alloc);
    auto kpmap_activate = (void(*)(struct thread *td)) kdlsym(pmap_activate);

	sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
	vmspace = kvmspace_alloc(sv_minuser, sv->sv_maxuser);
	if (!vmspace)
	{
		WriteLog(LL_Error, "PS4GDB::PS4GDBMain Could not allocate new vm space\n");
		return;
	}

    // setup vmspace
    WriteLog(LL_Info, "PS4GDB::PS4GDBMain Activate vmspace...");
	p->p_vmspace = vmspace;
	if (p == curthread->td_proc)
		kpmap_activate(curthread);

    WriteLog(LL_Info, "PS4GDB::PS4GDBMain Creating stdin/out/err...\n");
    kopen_t("/dev/console", O_RDONLY,0, curthread);
    kopen_t("/dev/console", O_RDONLY,0, curthread);
    kopen_t("/dev/console", O_RDONLY,0, curthread);

	WriteLog(LL_Info, "PS4GDB::PS4GDBMain Starting server: CMD PORT 8146 - PROTOCOL PORT 8846\n");
	//Print thread info
    struct thread *td = curthread;
    /* Resolve credentials */
	struct ucred *cred;
    cred = td->td_proc->p_ucred;
    LOG_DBG("sceAuthID: 0x%llx\n",cred->cr_sceAuthID);
    LOG_DBG("cr_sceCaps[0]: 0x%llx\n",cred->cr_sceCaps[0]);
    LOG_DBG("cr_sceCaps[1]: 0x%llx\n",cred->cr_sceCaps[1]);
    // Start server
	LOG_DBG("PID: %d\n", ps4gdb_sys_getpid());
	LOG_DBG("Starting server...\n");
    ps4gdb_start_cmd_server(8146,8846);
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Hook.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Logger.hpp>
#include <Utils/Kdlsym.hpp>
#include <Utils/SysWrappers.hpp>

#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/MessageManager.hpp>
#include <Plugins/PluginManager.hpp>

#include <OrbisOS/Utilities.hpp>

#include <Mira.hpp>

extern "C"
{
    #include <Messaging/Rpc/rpc.pb-c.h>

    #include <sys/uio.h>
	#include <sys/proc.h>
	#include <sys/ioccom.h>
    #include <sys/ptrace.h>
    #include <sys/mman.h>
    #include <sys/sx.h>
    #include <sys/errno.h>
    #include <sys/wait.h>
    #include <sys/socket.h>

    #include <vm/vm.h>
	#include <vm/pmap.h>

    #include <machine/reg.h>
    #include <machine/param.h>
    #include <machine/frame.h>
	#include <machine/psl.h>
	#include <machine/pmap.h>
	#include <machine/segments.h>

	#include <sys/eventhandler.h>
};

namespace Mira
{
    namespace Plugins
    {
        class PS4GDB : public Utils::IModule
        {
        public:
            PS4GDB();
            virtual ~PS4GDB();

            virtual const char* GetName() override { return "PS4GDB"; }
            virtual const char* GetDescription() override { return "PS4 userland gdbstub"; }

            // Module callbacks
            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

        protected:
        private:
            // Necessary methods
            static void PS4GDBMain(void *);
            bool SpawnKproc();
            static void GetRoot();
        };
    }
}


code:
/****************************************************************************

		THIS SOFTWARE IS NOT COPYRIGHTED

   HP offers the following for use in the public domain.  HP makes no
   warranty with regard to the software or it's performance and the
   user accepts the software "AS IS" with all faults.

   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

****************************************************************************/

/****************************************************************************
 *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
 *
 *  Module name: remcom.c $
 *  Revision: 1.34 $
 *  Date: 91/03/09 12:29:49 $
 *  Contributor:     Lake Stevens Instrument Division$
 *
 *  Description:     low level support for gdb debugger. $
 *
 *  Considerations:  only works on target hardware $
 *
 *  Written by:      Glenn Engel $
 *  ModuleState:     Experimental $
 *
 *  NOTES:           See Below $
 *
 *  Modified for 386 by Jim Kingdon, Cygnus Support.
 *
 *  To enable debugger support, two things need to happen.  One, a
 *  call to set_debug_traps() is necessary in order to allow any breakpoints
 *  or error conditions to be properly intercepted and reported to gdb.
 *  Two, a breakpoint needs to be generated to begin communication.  This
 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
 *  simulates a breakpoint by executing a trap #1.
 *
 *  The external function exceptionHandler() is
 *  used to attach a specific handler to a specific 386 vector number.
 *  It should use the same privilege level it runs at.  It should
 *  install it as an interrupt gate so that interrupts are masked
 *  while the handler runs.
 *
 *  Because gdb will sometimes write to the stack area to execute function
 *  calls, this program cannot rely on using the supervisor stack so it
 *  uses it's own stack area reserved in the int array remcomStack.
 *
 *************
 *
 *    The following gdb commands are supported:
 *
 * command          function                               Return value
 *
 *    g             return the value of the CPU registers  hex data or ENN
 *    G             set the value of the CPU registers     OK or ENN
 *
 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
 *
 *    c             Resume at current address              SNN   ( signal NN)
 *    cAA..AA       Continue at address AA..AA             SNN
 *
 *    s             Step one instruction                   SNN
 *    sAA..AA       Step one instruction from AA..AA       SNN
 *
 *    k             kill
 *
 *    ?             What was the last sigval ?             SNN   (signal NN)
 *
 * All commands and responses are sent with a packet which includes a
 * checksum.  A packet consists of
 *
 * $<packet info>#<checksum>.
 *
 * where
 * <packet info> :: <characters representing the command or response>
 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
 *
 * When a packet is received, it is first acknowledged with either '+' or '-'.
 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
 *
 * Example:
 *
 * Host:                  Reply:
 * $m0,10#2a               +$00010203040506070809101112131415#42
 *
 ****************************************************************************/

extern "C"
{
    #include <sys/param.h>
    #include <sys/types.h>
    #include <sys/filedesc.h>
    #include <sys/proc.h>
    #include <sys/stdint.h>
    #include <sys/fcntl.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/mman.h>
    #include <sys/unistd.h>
    #include <vm/vm.h>
    #include <sys/malloc.h>
    #include <sys/ptrace.h>
    #include <machine/reg.h>
    #include <sys/wait.h>
}

#include "gdbstub.hpp"
#include "ptrace.hpp"
#include "kdl.h"
#include "log.h"
#include "syscalls.hpp"

extern int GDB_SERVER_PID;
extern int gdb_server_socket;

/************************************************************************
 *
 * external low-level support routines
 */

int gdb_strlen(char *str);
int gdb_vm_fault_disable_pagefaults();
void gdb_vm_fault_enable_pagefaults(int val);

void putDebugChar(char c)
{
    unsigned char tmpStr[2];
    tmpStr[1] = 0;
    tmpStr[0] = c;
    LOG_SIMPLE("%s",tmpStr);
    gdb_putDebugChar((unsigned char)c);
}

unsigned char getDebugChar()
{
    unsigned char tmpStr[2];
    tmpStr[1] = 0;

    unsigned char c = gdb_getDebugChar();
    tmpStr[0] = c;
    LOG_SIMPLE("%s",tmpStr);
    return c;
}

/************************************************************************/
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
/* at least NUMREGBYTES*2 are needed for register packets */
#define BUFMAX 0x4000 //4096*4

enum amd64_regnum
{
    AMD64_RAX_REGNUM,
    AMD64_RBX_REGNUM,
    AMD64_RCX_REGNUM,
    AMD64_RDX_REGNUM,
    AMD64_RSI_REGNUM,
    AMD64_RDI_REGNUM,
    AMD64_RBP_REGNUM,
    AMD64_RSP_REGNUM,
    AMD64_R8_REGNUM,
    AMD64_R9_REGNUM,
    AMD64_R10_REGNUM,
    AMD64_R11_REGNUM,
    AMD64_R12_REGNUM,
    AMD64_R13_REGNUM,
    AMD64_R14_REGNUM,
    AMD64_R15_REGNUM,
    AMD64_RIP_REGNUM,
    AMD64_EFLAGS_REGNUM,
    AMD64_CS_REGNUM,
    AMD64_SS_REGNUM,
    AMD64_DS_REGNUM,
    AMD64_ES_REGNUM,
    AMD64_FS_REGNUM,
    AMD64_GS_REGNUM,
    AMD64_ST0_REGNUM = 24,
    AMD64_ST1_REGNUM,
    AMD64_FCTRL_REGNUM = AMD64_ST0_REGNUM + 8,
    AMD64_FSTAT_REGNUM = AMD64_ST0_REGNUM + 9,
    AMD64_FTAG_REGNUM = AMD64_ST0_REGNUM + 10,
    AMD64_XMM0_REGNUM = 40,
    AMD64_XMM1_REGNUM,
    AMD64_MXCSR_REGNUM = AMD64_XMM0_REGNUM + 16,
    AMD64_YMM0H_REGNUM,
    AMD64_YMM15H_REGNUM = AMD64_YMM0H_REGNUM + 15,
    AMD64_BND0R_REGNUM = AMD64_YMM15H_REGNUM + 1,
    AMD64_BND3R_REGNUM = AMD64_BND0R_REGNUM + 3,
    AMD64_BNDCFGU_REGNUM,
    AMD64_BNDSTATUS_REGNUM,
    AMD64_XMM16_REGNUM,
    AMD64_XMM31_REGNUM = AMD64_XMM16_REGNUM + 15,
    AMD64_YMM16H_REGNUM,
    AMD64_YMM31H_REGNUM = AMD64_YMM16H_REGNUM + 15,
    AMD64_K0_REGNUM,
    AMD64_K7_REGNUM = AMD64_K0_REGNUM + 7,
    AMD64_ZMM0H_REGNUM,
    AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31,
    AMD64_PKRU_REGNUM,
    AMD64_FSBASE_REGNUM,
    AMD64_GSBASE_REGNUM
};

/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */

static const char hexchars[]="0123456789abcdef";

/* Number of registers.  */
#define NUMREGS 14

/* Number of bytes of registers.  */
#define NUMREGBYTES ((NUMREGS) * 8)

/*
 * these should not be static cuz they can be used outside this module
 */

/***************************  ASSEMBLY CODE MACROS *************************/

#define BREAKPOINT() asm("   int $3");

/* Put the error code here just in case the user cares.  */

/* Likewise, the vector number here (since GDB only gets the signal
   number through the usual means, and that's not very specific).  */

/* GDB stores segment registers in 32-bit words (that's just the way
   m-i386v.h is written).  So zero the appropriate areas in registers.  */
/*
 * remcomHandler is a front end for handle_exception.  It moves the
 * stack pointer into an area reserved for debugger use.
 */
int hex (char ch)
{
    if ((ch >= 'a') && (ch <= 'f'))
        return (ch - 'a' + 10);
    if ((ch >= '0') && (ch <= '9'))
        return (ch - '0');
    if ((ch >= 'A') && (ch <= 'F'))
        return (ch - 'A' + 10);
    return (-1);
}

/* scan for the sequence $<data>#<checksum>     */
char *remcomInBuffer = NULL;

unsigned char *getpacket (void)
{
	PS4GDB_kmalloc();
	PS4GDB_kM_TEMP();

    if(remcomInBuffer == NULL)
    {
        remcomInBuffer = (char*)kmalloc(4096*4,kM_TEMP,0x102);
        LOG_DBG("remcomInBuffer allocated at 0x%llx\n", remcomInBuffer);
    }

    LOG_SIMPLE("\n<-");

    unsigned char *buffer = (unsigned char *)remcomInBuffer;
    unsigned char checksum;
    unsigned char xmitcsum;
    int count;
    char ch;

    while (1)
    {
        /* wait around for the start character, ignore all other characters */
        while ((ch = getDebugChar ()) != '$')
            ;

retry:
        checksum = 0;
        xmitcsum = -1;
        count = 0;

        /* now, read until a # or end of buffer is found */
        while (count < BUFMAX - 1)
        {
            ch = getDebugChar ();
            if (ch == '$')
                goto retry;
            if (ch == '#')
                break;
            checksum = checksum + ch;
            buffer[count] = ch;
            count = count + 1;
        }
        buffer[count] = 0;

        if (ch == '#')
        {
            ch = getDebugChar ();
            xmitcsum = hex (ch) << 4;
            ch = getDebugChar ();
            xmitcsum += hex (ch);

            if (checksum != xmitcsum)
            {

                putDebugChar ('-');	/* failed checksum */
            }
            else
            {
                putDebugChar ('+');	/* successful transfer */

                /* if a sequence char is present, reply the sequence ID */
                if (buffer[2] == ':')
                {
                    putDebugChar (buffer[0]);
                    putDebugChar (buffer[1]);

                    return &buffer[3];
                }

                return &buffer[0];
            }
        }
    }
}

/* send the packet in buffer.  */
void putpacket (unsigned char *buffer)
{
    unsigned char checksum;
    int count;
    char ch;

    LOG_SIMPLE("\n->", buffer);

    /*  $<packet info>#<checksum>.  */
    do
    {
        putDebugChar ('$');
        checksum = 0;
        count = 0;

        while ((ch = buffer[count]))
        {
            putDebugChar (ch);
            checksum += ch;
            count += 1;
        }

        putDebugChar ('#');
        putDebugChar (hexchars[checksum >> 4]);
        putDebugChar (hexchars[checksum % 16]);

    }
    while (getDebugChar () != '+');
}

/* Address of a routine to RTE to if we get a memory fault.  */
static void (*volatile mem_fault_routine) () = NULL;

/* Indicate to caller of mem2hex or hex2mem that there has been an
   error.  */
static volatile int mem_err = 0;

void set_mem_err (void)
{
    mem_err = 1;
}

/* These are separate functions so that they are so short and sweet
   that the compiler won't save any registers (if there is a fault
   to mem_fault, they won't get restored, so there better not be any
   saved).  */
int get_char (char *addr)
{
    return *addr;
}

void set_char (char *addr, int val)
{
    *addr = val;
}

/* convert the memory pointed to by mem into hex, placing result in buf */
/* return a pointer to the last char put in buf (null) */
/* If MAY_FAULT is non-zero, then we should set mem_err in response to
   a fault; if zero treat a fault like any other fault in the stub.  */
char *mem2hex_ptrace (char *mem, char *buf, int count, int may_fault)
{
   	PS4GDB_kmalloc();
	PS4GDB_kfree();
	PS4GDB_kM_TEMP();

    int i;
    unsigned char ch;
    mem_err = 0;

    uint8_t *readAddr;
    size_t allocSize;
    if(count > 4096) {
        allocSize = count;
    } else {
        allocSize = 4096;
    }

    readAddr = (uint8_t *)kmalloc(allocSize,kM_TEMP,0x102);

    // Read memory address using ptrace
    int r = ptrace_io(GDB_SERVER_PID, PIOD_READ_I, mem, readAddr, count);
    if (r == 0) {
        mem = (char*)readAddr;

        for (i = 0; i < count; i++)
        {
            ch = get_char (mem++);
            if(mem_err == 1)
                ch = 0x00;

            *buf++ = hexchars[ch >> 4];
            *buf++ = hexchars[ch % 16];
        }
        *buf = 0;
    }
    else {
        mem_err = 1;
    }
    kfree((void*)readAddr,kM_TEMP);
    return (buf);
}

char *mem2hex (char *mem, char *buf, int count, int may_fault)
{
    int i;
    unsigned char ch;
    mem_err = 0;

    for (i = 0; i < count; i++)
    {
        ch = get_char (mem++);
        if(mem_err == 1)
        {
            ch = 0x00;
        }

        *buf++ = hexchars[ch >> 4];
        *buf++ = hexchars[ch % 16];
    }
    *buf = 0;

    return (buf);
}

/* convert the hex array pointed to by buf into binary to be placed in mem */
/* return a pointer to the character AFTER the last byte written */
char *hex2mem (char *buf, char *mem, int count, int may_fault)
{
    int i;
    unsigned char ch;

    if (may_fault)
        mem_fault_routine = set_mem_err;
    for (i = 0; i < count; i++)
    {
        ch = hex (*buf++) << 4;
        ch = ch + hex (*buf++);
        set_char (mem++, ch);
        if (may_fault && mem_err)
            return (mem);
    }
    if (may_fault)
        mem_fault_routine = NULL;
    return (mem);
}

char *hex2mem_ptrace (char *buf, char *mem, int count, int may_fault)
{
   	PS4GDB_kmalloc();
	PS4GDB_kfree();
	PS4GDB_kM_TEMP();

    int i;
    unsigned char ch;

    // alloc temp buffer
    char *writeAddr;
    size_t allocSize;
    if(count > 4096) {
        allocSize = count;
    } else {
        allocSize = 4096;
    }

    writeAddr = (char*)kmalloc(allocSize,kM_TEMP,0x102);
    char *helper = writeAddr;

    // Write received hex bytes into allocated buffer
    for (i = 0; i < count; i++)
    {
        ch = hex (*buf++) << 4;
        ch = ch + hex (*buf++);
        set_char (helper++, ch);
    }

    // Write bytes into process memory
    int r = (int)ptrace_io(GDB_SERVER_PID,PT_WRITE_I,mem,writeAddr,count);

    if(r != 0)
        mem_err = 1;
    else
        mem_err = 0;

    kfree((void*)writeAddr,kM_TEMP);
    return (mem);
}

/* this function takes the 386 exception vector and attempts to
   translate this number into a unix compatible signal value */
int computeSignal (int exceptionVector)
{
    int sigval;
    switch (exceptionVector)
    {
    case 0:
        sigval = 8;
        break;			/* divide by zero */
    case 1:
        sigval = 5;
        break;			/* debug exception */
    case 3:
        sigval = 5;
        break;			/* breakpoint */
    case 4:
        sigval = 16;
        break;			/* into instruction (overflow) */
    case 5:
        sigval = 16;
        break;			/* bound instruction */
    case 6:
        sigval = 4;
        break;			/* Invalid opcode */
    case 7:
        sigval = 8;
        break;			/* coprocessor not available */
    case 8:
        sigval = 7;
        break;			/* double fault */
    case 9:
        sigval = 11;
        break;			/* coprocessor segment overrun */
    case 10:
        sigval = 11;
        break;			/* Invalid TSS */
    case 11:
        sigval = 11;
        break;			/* Segment not present */
    case 12:
        sigval = 11;
        break;			/* stack exception */
    case 13:
        sigval = 11;
        break;			/* general protection */
    case 14:
        sigval = 11;
        break;			/* page fault */
    case 16:
        sigval = 7;
        break;			/* coprocessor error */
    default:
        sigval = 7;		/* "software generated" */
    }
    return (sigval);
}

/**********************************************/
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
/* RETURN NUMBER OF CHARS PROCESSED           */
/**********************************************/
int hexToInt (char **ptr, unsigned long long *intValue)
{
    int numChars = 0;
    int hexValue;

    *intValue = 0;

    while (**ptr)
    {
        hexValue = hex (**ptr);
        if (hexValue >= 0)
        {
            *intValue = (*intValue << 4) | hexValue;
            numChars++;
        }
        else
            break;

        (*ptr)++;
    }

    return (numChars);
}

void createTempStr(char *src, char *dst, char separator)
{
    int i = 0;

    for(i = 0; ; i++)
        if(src[i] == separator)
        {
            dst[i] = 0x00;
            break;
        }
        else
            dst[i] = src[i];

    return;
}

unsigned long long hextoull(char *ptr)
{
    unsigned long long value = ps4gdb_strtoul(ptr, NULL, 16);
    return value;
}

static uint64_t registers[100];

static char tmpBuff[1024];

void update_registers() {
    struct reg regs;
    ptrace_get_regs(GDB_SERVER_PID,&regs);
    registers[AMD64_RAX_REGNUM] = regs.r_rax;
    registers[AMD64_RBX_REGNUM] = regs.r_rbx;
    registers[AMD64_RCX_REGNUM] = regs.r_rcx;
    registers[AMD64_RDX_REGNUM] = regs.r_rdx;
    registers[AMD64_RDI_REGNUM] = regs.r_rdi;
    registers[AMD64_RSI_REGNUM] = regs.r_rsi;
    registers[AMD64_RSP_REGNUM] = regs.r_rsp;
    registers[AMD64_RBP_REGNUM] = regs.r_rbp;
    registers[AMD64_R8_REGNUM] = regs.r_r8;
    registers[AMD64_R9_REGNUM] = regs.r_r9;
    registers[AMD64_R10_REGNUM] = regs.r_r10;
    registers[AMD64_R11_REGNUM] = regs.r_r11;
    registers[AMD64_R12_REGNUM] = regs.r_r12;
    registers[AMD64_R13_REGNUM] = regs.r_r13;
    registers[AMD64_R14_REGNUM] = regs.r_r14;
    registers[AMD64_R15_REGNUM] = regs.r_r15;
    registers[AMD64_RIP_REGNUM] = regs.r_rip;
    registers[AMD64_CS_REGNUM] = regs.r_cs;
    registers[AMD64_SS_REGNUM] = regs.r_ss;
    registers[AMD64_DS_REGNUM] = regs.r_ds;
    registers[AMD64_ES_REGNUM] = regs.r_es;
    registers[AMD64_FS_REGNUM] = regs.r_fs;
    registers[AMD64_GS_REGNUM] = regs.r_gs;
    registers[AMD64_EFLAGS_REGNUM] = regs.r_rflags;
}

void write_registers() {
    struct reg regs;
    ptrace_get_regs(GDB_SERVER_PID,&regs);
    regs.r_rax = registers[AMD64_RAX_REGNUM];
    regs.r_rbx = registers[AMD64_RBX_REGNUM];
    regs.r_rcx = registers[AMD64_RCX_REGNUM];
    regs.r_rdx = registers[AMD64_RDX_REGNUM];
    regs.r_rdi = registers[AMD64_RDI_REGNUM];
    regs.r_rsi = registers[AMD64_RSI_REGNUM];
    regs.r_rsp = registers[AMD64_RSP_REGNUM];
    regs.r_rbp = registers[AMD64_RBP_REGNUM];
    regs.r_r8 = registers[AMD64_R8_REGNUM];
    regs.r_r9 = registers[AMD64_R9_REGNUM];
    regs.r_r10 = registers[AMD64_R10_REGNUM];
    regs.r_r11 = registers[AMD64_R11_REGNUM];
    regs.r_r12 = registers[AMD64_R12_REGNUM];
    regs.r_r13 = registers[AMD64_R13_REGNUM];
    regs.r_r14 = registers[AMD64_R14_REGNUM];
    regs.r_r15 = registers[AMD64_R15_REGNUM];
    regs.r_rip = registers[AMD64_RIP_REGNUM];
    regs.r_cs = registers[AMD64_CS_REGNUM];
    regs.r_ss = registers[AMD64_SS_REGNUM];
    regs.r_ds = registers[AMD64_DS_REGNUM];
    regs.r_es = registers[AMD64_ES_REGNUM];
    regs.r_fs = registers[AMD64_FS_REGNUM];
    regs.r_gs = registers[AMD64_GS_REGNUM];
    regs.r_rflags = registers[AMD64_EFLAGS_REGNUM];
    ptrace_set_regs(GDB_SERVER_PID,&regs);
}

void print_register_info(int gdb_i386vector, int errorCode)
{
    update_registers();

    LOG_DBG("received interrupt %02d - errorCode: 0x%llx\n", gdb_i386vector, errorCode);
    LOG_DBG("RAX: 0x%016llx\t\tRBX:  0x%016llx\n",registers[AMD64_RAX_REGNUM],registers[AMD64_RBX_REGNUM]);
    LOG_DBG("RCX: 0x%016llx\t\tRDX:  0x%016llx\n",registers[AMD64_RCX_REGNUM],registers[AMD64_RDX_REGNUM]);
    LOG_DBG("RSI: 0x%016llx\t\tRDI:  0x%016llx\n",registers[AMD64_RSI_REGNUM],registers[AMD64_RDI_REGNUM]);
    LOG_DBG("RBP: 0x%016llx\t\tRSP:  0x%016llx\n",registers[AMD64_RBP_REGNUM],registers[AMD64_RSP_REGNUM]);
    LOG_DBG("R8:  0x%016llx\t\tR9:   0x%016llx\n",registers[AMD64_R8_REGNUM],registers[AMD64_R9_REGNUM]);
    LOG_DBG("R10: 0x%016llx\t\tR11:  0x%016llx\n",registers[AMD64_R10_REGNUM],registers[AMD64_R11_REGNUM]);
    LOG_DBG("R12: 0x%016llx\t\tR13:  0x%016llx\n",registers[AMD64_R12_REGNUM],registers[AMD64_R13_REGNUM]);
    LOG_DBG("R14: 0x%016llx\t\tR15:  0x%016llx\n",registers[AMD64_R14_REGNUM],registers[AMD64_R15_REGNUM]);
    LOG_DBG("RIP: 0x%016llx\t\tFLAGS:0x%016llx\n",registers[AMD64_RIP_REGNUM],registers[AMD64_EFLAGS_REGNUM]);
    LOG_DBG("CS:  0x%016llx\t\tSS:   0x%016llx\n",registers[AMD64_CS_REGNUM],registers[AMD64_SS_REGNUM]);
    LOG_DBG("DS:  0x%016llx\t\tES:   0x%016llx\n",registers[AMD64_DS_REGNUM],registers[AMD64_ES_REGNUM]);
    LOG_DBG("FS:  0x%016llx\t\tGS:   0x%016llx\n",registers[AMD64_FS_REGNUM],registers[AMD64_GS_REGNUM]);
}

/*
 * This function does all command procesing for interfacing to gdb.
 */
void handle_exception (int gdb_i386vector, unsigned long long *registersOld, int errorCode)
{
    PS4GDB_kavcontrol_sleep();
    PS4GDB_ksnprintf();
    PS4GDB_kmalloc();
	PS4GDB_kM_TEMP();
    LOG_DBG("gdb_stub: handle exception start...\n");

    char *remcomOutBuffer = (char*)kmalloc(4096*4,kM_TEMP,0x102);

    LOG_DBG("remcomOutBuffer allocated at 0x%llx\n", remcomOutBuffer);

    int Doexit = 0;

    print_register_info(gdb_i386vector,errorCode);

    int sigval;
    unsigned long long addr, length;
    char *ptr;
    int stat = 0;

    /* reply to host that an exception has occurred */
    sigval = computeSignal (gdb_i386vector);
    ptr = remcomOutBuffer;

    LOG_DBG("gdb_stub: Entering main loop...\n");

    while (1 == 1)
    {
        remcomOutBuffer[0] = 0;
        ptr = (char*)getpacket ();

        switch (*ptr++)
        {
            case '?':
                remcomOutBuffer[0] = 'S';
                remcomOutBuffer[1] = hexchars[sigval >> 4];
                remcomOutBuffer[2] = hexchars[sigval % 16];
                remcomOutBuffer[3] = 0;
                break;
            case 'd':
                //remote_debug = !(remote_debug);	/* toggle debug flag */
                break;
            case 'g':		/* return the value of the CPU registers */
                update_registers();
                mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
                break;
            case 'G':		/* set the value of the CPU registers - return OK */
                hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
                gdb_strcpy (remcomOutBuffer, "OK");
                break;
            case 'P':		/* set the value of a single CPU register - return OK */
            {
                int regno;
                regno = (int)ps4gdb_strtoul(ptr,NULL,16);
                ksnprintf(tmpBuff,1024,"%llx",regno);
                ptr += gdb_strlen(tmpBuff)+1;
                hex2mem (ptr, (char *) &registers[regno], 8, 0);
                write_registers();
                gdb_strcpy (remcomOutBuffer, "OK");
                break;
            }

            /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
            case 'm':
                //LOG_DBG("got m packet! Ignoring...\n");
                //return;
                /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
                //LOG_DBG("COMMAND####%s######\n",ptr);
                addr = ps4gdb_strtoul(ptr, NULL, 16);
                ksnprintf(tmpBuff,1024,"%llx",addr);
                ptr += gdb_strlen(tmpBuff);
                if (*(ptr++) == ',')
                {
                    if (hexToInt (&ptr, &length))
                    {
                        ptr = 0;
                        mem_err = 0;
                        mem2hex_ptrace((char *) addr, remcomOutBuffer, length, 1);
                        if (mem_err)
                        {
                            gdb_strcpy (remcomOutBuffer, "E03");
                        }
                    }
                }

                if (ptr)
                {
                    gdb_strcpy (remcomOutBuffer, "E01");
                }

                break;

            /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
            case 'M':
                /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
                if (hexToInt (&ptr, &addr))
                    if (*(ptr++) == ',')
                        if (hexToInt (&ptr, &length))
                            if (*(ptr++) == ':')
                            {
                                mem_err = 0;
                                hex2mem_ptrace (ptr, (char *) addr, length, 1);
                                if (mem_err)
                                {
                                    gdb_strcpy (remcomOutBuffer, "E03");
                                }
                                else
                                {
                                    gdb_strcpy (remcomOutBuffer, "OK");
                                }
                                ptr = 0;
                            }
                if (ptr)
                {
                    gdb_strcpy (remcomOutBuffer, "E02");
                }
                break;
            /* cAA..AA    Continue at address AA..AA(optional) */
            /* sAA..AA   Step one instruction from AA..AA(optional) */
            case 's':
            case 'c':
                ptrace_clearstep(GDB_SERVER_PID);
                ptrace_continue(GDB_SERVER_PID);
                kavcontrol_sleep(100000);
                stat = 0;
                ps4gdb_sys_wait4(GDB_SERVER_PID,&stat,WUNTRACED,0);
                update_registers();
                remcomOutBuffer[0] = 'S';
                remcomOutBuffer[1] = hexchars[5 >> 4];
                remcomOutBuffer[2] = hexchars[5 % 16];
                remcomOutBuffer[3] = 0;
                break;
            case 'p':
                addr = ps4gdb_strtoul(ptr,NULL,16);
                mem2hex ((char *) &registers[addr], remcomOutBuffer, 8, 0);
                break;
            /* kill the program */
            case 'k':		/* do nothing */
                ptrace_clearstep(GDB_SERVER_PID);
                ptrace_detach(GDB_SERVER_PID);
                ps4gdb_sys_shutdown(gdb_server_socket,SHUT_RDWR);
                ps4gdb_sys_close(gdb_server_socket);
                gdb_server_socket = -1;
                return;
                break;
            case 'q':
                if(startsWith("Supported",ptr) == 1) {
                    gdb_strcpy (remcomOutBuffer, "");
                } else if((startsWith("TStatus",ptr) == 1)) {
                    gdb_strcpy (remcomOutBuffer, "T0");
                } else {
                    gdb_strcpy (remcomOutBuffer, "");
                }
                break;
            case 'Z':
                gdb_strcpy (remcomOutBuffer, "");
                break;
            case 'v':
                if(startsWith("Cont?",ptr) == 1) {
                    gdb_strcpy (remcomOutBuffer, "vCont;c;C;s;S;t;r");
                } else if (startsWith("Cont;s",ptr) == 1) {
                    ptrace_setstep(GDB_SERVER_PID);
                    ptrace_step(GDB_SERVER_PID);
                    kavcontrol_sleep(100000);
                    stat = 0;
                    ps4gdb_sys_wait4(GDB_SERVER_PID,&stat,WUNTRACED,0);

                    update_registers();
                    remcomOutBuffer[0] = 'S';
                    remcomOutBuffer[1] = hexchars[5 >> 4];
                    remcomOutBuffer[2] = hexchars[5 % 16];
                    remcomOutBuffer[3] = 0;
                } else if (startsWith("Cont;c",ptr) == 1) {
                    ptrace_clearstep(GDB_SERVER_PID);
                    ptrace_continue(GDB_SERVER_PID);
                    stat = 0;
                    ps4gdb_sys_wait4(GDB_SERVER_PID,&stat,WUNTRACED,0);
                    update_registers();
                    // If we restart here, we probably have hit a breakpoint
                    // So we need to restore the original opcode
                    //ps4gdb_restore_breakpoint_opcode(registers[AMD64_RIP_REGNUM]);
                    remcomOutBuffer[0] = 'S';
                    remcomOutBuffer[1] = hexchars[5 >> 4];
                    remcomOutBuffer[2] = hexchars[5 % 16];
                    remcomOutBuffer[3] = 0;
                } else {
                    gdb_strcpy (remcomOutBuffer, "");
                }
                break;
        }			/* switch */

        /* reply to the request */
        putpacket ((unsigned char*)remcomOutBuffer);
        if(Doexit == 1)
            return;
    }
}


code:
#pragma once

extern "C"
{
    #include <sys/param.h>
    #include <sys/types.h>
    #include <sys/stdint.h>
}

void gdb_exceptionHandler(int exception_number, void *exception_address);
int gdb_start_server(int port, int pid);
void gdb_strcpy(char *dest, const char *src);
unsigned char gdb_getDebugChar();
int gdb_read(void *buff, int len);
void gdb_memset(void *buff, uint8_t value, int len);
void gdb_putDebugChar(unsigned char c);
int gdb_write(void *buff, int len);
void gdbstub_set_debug_traps (void);
int startsWith(const char *pre, const char *str);
unsigned long ps4gdb_strtoul(const char *nptr, char **endptr, int base);
int ps4gdb_start_cmd_server(int cmd_port, int gdb_port);


code:
#pragma once

#include <sys/param.h>
#include <sys/types.h>
#include <sys/filedesc.h>
#include <sys/stdint.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/unistd.h>
#include <vm/vm.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/sx.h>
#include <Utils/Kdlsym.hpp>

struct ps4gdb_sys_gen_uap{
	uint64_t p1;
	uint64_t p2;
	uint64_t p3;
	uint64_t p4;
	uint64_t p5;
	uint64_t p6;
	uint64_t p7;
};

#define PS4GDB_kprintf() auto kprintf = (void(*)(const char *format, ...))kdlsym(printf);
#define PS4GDB_kbzero() auto kbzero = (void(*)(void *ptr,int count))kdlsym(bzero);
#define PS4GDB_ksys_socket() auto ksys_socket = (int(*)(struct thread *, struct socket_args *))kdlsym(sys_socket);
#define PS4GDB_ksys_bind() auto ksys_bind = (int(*)(struct thread *, struct bind_args *))kdlsym(sys_bind);
#define PS4GDB_ksys_listen() auto ksys_listen = (int(*)(struct thread *, struct listen_args *))kdlsym(sys_listen);
#define PS4GDB_ksys_accept() auto ksys_accept = (int(*)(struct thread *, struct accept_args *))kdlsym(sys_accept);
#define PS4GDB_ksys_close() auto ksys_close = (int(*)(struct thread *, struct close_args *))kdlsym(sys_close);
#define PS4GDB_kkthread_add() auto kkthread_add = (int(*)(void (*func)(void *), void *arg, struct proc *procp,struct thread **newtdpp, int flags, int pages,	const char *fmt, ...))kdlsym(kthread_add);
#define PS4GDB_ksys_read() auto ksys_read = (int(*)(struct thread *, struct read_args *))kdlsym(sys_read);
#define PS4GDB_ksys_write() auto ksys_write = (int(*)(struct thread *, struct write_args *))kdlsym(sys_write);
#define PS4GDB_kM_TEMP() struct malloc_type *kM_TEMP = (struct malloc_type *)kdlsym(M_TEMP);
#define PS4GDB_kmalloc() auto kmalloc = (void*(*)(unsigned long size, struct malloc_type *type, int flags))kdlsym(malloc);
#define PS4GDB_kfree() auto kfree = (void(*)(void *addr, struct malloc_type *type))kdlsym(free);
#define PS4GDB_ksys_open() auto ksys_open = (int (*)(struct thread *, struct open_args *))kdlsym(sys_open);
#define PS4GDB_ksys_getpid() auto ksys_getpid = (int (*)(struct thread *))kdlsym(sys_getpid);
#define PS4GDB_kkproc_exit() auto kkproc_exit = (int(*)(int code))kdlsym(kproc_exit);
#define PS4GDB_ksys_mmap() auto ksys_mmap = (void*(*)(struct thread *, struct mmap_args *))kdlsym(sys_mmap);
#define PS4GDB_ksys_munmap() auto ksys_munmap = (void*(*)(struct thread *, struct munmap_args *))kdlsym(sys_munmap);
#define PS4GDB_kkthread_exit() auto kkthread_exit = (void(*)())kdlsym(kthread_exit);
#define PS4GDB_kvmspace_alloc() auto kvmspace_alloc = (struct vmspace*(*)(vm_offset_t min, vm_offset_t max))kdlsym(vmspace_alloc);
#define PS4GDB_kpmap_activate() auto kpmap_activate = (void(*)(struct thread *td))kdlsym(pmap_activate);
#define PS4GDB_kstrlen() auto kstrlen = (int(*)(const char *str))kdlsym(strlen);
#define PS4GDB_kstrcpy() auto kstrcpy = (char*(*)( char *destination, const char *source))kdlsym(strcpy);
#define PS4GDB_kcopyout() auto kcopyout = (int(*)(const void *kaddr, void *uaddr, size_t len))kdlsym(copyout);
#define PS4GDB_ksys_shutdown() auto ksys_shutdown = (int(*)(struct thread *td,struct ps4gdb_sys_gen_uap *uap))kdlsym(sys_shutdown);
#define PS4GDB_ksys_ptrace() auto ksys_ptrace = (int(*)(struct thread *td,struct ps4gdb_sys_gen_uap *uap))kdlsym(sys_ptrace);
#define PS4GDB_ksys_wait4() auto ksys_wait4 = (int(*)(struct thread *td,struct ps4gdb_sys_gen_uap *uap))kdlsym(sys_wait4);
#define PS4GDB_ksys_sysctl() auto ksys_sysctl = (int(*)(struct thread *td,struct ps4gdb_sys_gen_uap *uap))kdlsym(sys_sysctl);
#define PS4GDB_ksnprintf() auto ksnprintf = (int(*)( char * s, size_t n, const char * format, ... ))kdlsym(snprintf);
#define PS4GDB_kavcontrol_sleep() auto kavcontrol_sleep = (int(*)(int amount))kdlsym(avcontrol_sleep);


code:
#include "kdl.h"

#define LOG_ERROR(fmt, ...) do {  if (_DEBUG) { PS4GDB_kprintf(); kprintf("[%s] ERROR - " fmt, __FUNCTION__, ##__VA_ARGS__);  } } while (0)
#define LOG_DBG(fmt, ...) do {  if (_DEBUG) {PS4GDB_kprintf(); kprintf("[%s] " fmt, __FUNCTION__, ##__VA_ARGS__); }} while (0)
#define LOG_SIMPLE(fmt, ...) do {  if (_DEBUG) {PS4GDB_kprintf(); kprintf("%s" fmt, "", ##__VA_ARGS__); }} while (0)


code:
extern "C"
{
	#include <sys/param.h>
	#include <sys/types.h>
	#include <sys/filedesc.h>
	#include <sys/proc.h>
	#include <sys/stdint.h>
	#include <sys/fcntl.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <sys/mman.h>
	#include <sys/unistd.h>
	#include <vm/vm.h>
	#include <sys/malloc.h>
	#include <sys/errno.h>
	#include <sys/sx.h>
	#include "log.h"
}

#include <Utils/Kdlsym.hpp>
#include "kdl.h"
#include "syscalls.hpp"

int ReadBytes(int socket, int x, void* buffer)
{
	int bytesRead = 0;
    int result;
	uint8_t *buf = (uint8_t*)buffer;
    while (bytesRead < x)
    {
        result = ps4gdb_sys_read(socket, buf, x - bytesRead);

		if (result < 0 ){
			LOG_ERROR("ps4ninja_read returned %d\n",result);
			return -1;
		}else if(result != 0){
			LOG_DBG("Received %d bytes\n",result);
			bytesRead += result;
			buf += result;
		}
    }
    return 0;
}


code: int ReadBytes(int socket, int x, void* buffer);


code:
extern "C"
{
#include <sys/param.h>
#include <sys/types.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/stdint.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <vm/vm.h>
#include <sys/malloc.h>
#include <sys/sysproto.h>
#include <sys/param.h>
#include <sys/ctype.h>
#include <sys/limits.h>
#include "log.h"
#include <sys/wait.h>
}

#include "gdbstub.hpp"
#include "syscalls.hpp"
#include "ptrace.hpp"
#include <Utils/SysWrappers.hpp>

int gdb_server_socket = -1;
int gdb_server_setup = 0;
extern int GDB_SERVER_PORT;
extern int GDB_SERVER_PID;

/*
 * Convert a string to an unsigned long integer.
 *
 * Ignores `locale' stuff.  Assumes that the upper and lower case
 * alphabets and digits are each contiguous.
 */
unsigned long ps4gdb_strtoul(const char *nptr, char **endptr, int base)
{
	const char *s = nptr;
	unsigned long acc;
	unsigned char c;
	unsigned long cutoff;
	int neg = 0, any, cutlim;

	/*
	 * See strtol for comments as to the logic used.
	 */
	do {
		c = *s++;
	} while (isspace(c));
	if (c == '-') {
		neg = 1;
		c = *s++;
	} else if (c == '+')
		c = *s++;
	if ((base == 0 || base == 16) &&
	    c == '0' && (*s == 'x' || *s == 'X')) {
		c = s[1];
		s += 2;
		base = 16;
	}
	if (base == 0)
		base = c == '0' ? 8 : 10;
	cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
	cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
	for (acc = 0, any = 0;; c = *s++) {
		if (!isascii(c))
			break;
		if (isdigit(c))
			c -= '0';
		else if (isalpha(c))
			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
		else
			break;
		if (c >= base)
			break;
		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
			any = -1;
		else {
			any = 1;
			acc *= base;
			acc += c;
		}
	}
	if (any < 0) {
		acc = ULONG_MAX;
	} else if (neg)
		acc = -acc;
	if (endptr != NULL)
		*endptr = __DECONST(char *, any ? s - 1 : nptr);
	return (acc);
}

int startsWith(const char *pre, const char *str)
{
    char cp;
    char cs;

    if (!*pre)
        return 1;

    while ((cp = *pre++) && (cs = *str++)){
        if (cp != cs)
            return 0;
    }

    if (!cs)
        return 0;

    return 1;
}

int gdb_strlen(char *str)
{
	const char *s;
	for (s = str; *s; ++s){}
	return (s - str);
}

int gdb_write(void *buff, int len)
{
	return ps4gdb_sys_write(gdb_server_socket,buff,len);
}

void gdb_close_client_socket()
{
    ps4gdb_sys_close(gdb_server_socket);
	return;
}

void gdb_putDebugChar(unsigned char c)
{
	if(gdb_server_socket != -1)
		gdb_write(&c,1);
}

int gdb_read(void *buff, int len)
{
	// If no connection is available, start server
	if(gdb_server_socket == -1)
	{
		gdb_server_socket = gdb_start_server(GDB_SERVER_PORT,GDB_SERVER_PID);
	}

	return ps4gdb_sys_read(gdb_server_socket,buff,len);
}

unsigned char gdb_getDebugChar()
{
	unsigned char c = 0x00;

	// If no connection is available, start server
	if(gdb_server_socket == -1)
	{
		gdb_server_socket = gdb_start_server(GDB_SERVER_PORT,GDB_SERVER_PID);
	}
	while(gdb_read(&c,1) != 1){  }

	return c;
}

void gdb_strcpy(char *dest, const char *src)
{
    size_t i;
    for (i = 0; src[i] != '\0'; i++)
        dest[i] = src[i];
    dest[i] = '\0';
}

void gdb_exceptionHandler(int exception_number, void *exception_address)
{

}

void gdb_memset(void *buff, uint8_t value, int len)
{
	uint8_t *tmp = (uint8_t*)buff;

	int i = 0;
	for(i = 0; i < len; i++)
		tmp[i] = value;

	return;
}

extern int errno;
void handle_exception (int gdb_i386vector, unsigned long long *registersOld, int errorCode);
uint8_t *get_process_list(uint64_t *len);

int ps4gdb_start_cmd_server(int cmd_port, int gdb_port)
{
    PS4GDB_kkproc_exit();
    LOG_DBG("Starting server...\n");
    GDB_SERVER_PORT = gdb_port;

    int server_socket = ps4gdb_sys_socket(AF_INET, SOCK_STREAM, 0);
    if(server_socket < 0){
        LOG_DBG("Failed to create server socket. errno: %d\n",errno);
        return server_socket;
    }

    int r = ps4gdb_sys_bind(server_socket,cmd_port);
	if(r != 0){
		LOG_ERROR("sys_bind failed. errno: %d\n",errno);
		return -1;
	}

	// Preparing to listen
	LOG_DBG("Starting to listen...\n");
	r = ps4gdb_sys_listen(server_socket, 10);
	if(r != 0){
		LOG_ERROR("sys_listen returned %d\n",errno);
		return -1;
	}

	for(;;){
		// Accept connections
		LOG_DBG("Accepting connections...\n");
		int client = ps4gdb_sys_accept(server_socket,(struct sockaddr *)NULL,0);
		if(client == -1){
            LOG_ERROR("sys_accept. errno %d\n",errno);
			ps4gdb_sys_shutdown(server_socket,SHUT_RDWR);
			ps4gdb_sys_close(server_socket);
			return -1;
		} else {
            LOG_DBG("Got connection...\n");
            uint64_t dataLen;
            struct kinfo_proc *kipp = (struct kinfo_proc *)get_process_list(&dataLen);
            ps4gdb_sys_write(client,&dataLen,8);
            LOG_DBG("Written data len\n");
            ps4gdb_sys_write(client,kipp,dataLen);
            LOG_DBG("Written proc info\n");
            ps4gdb_sys_munmap(kipp,dataLen);

            // Read PID to attach
            ps4gdb_sys_read(client,&GDB_SERVER_PID,4);

            if(GDB_SERVER_PID != -1)
            {
                if(GDB_SERVER_PID == -2){
                    LOG_DBG("Received command -2, destroying process...\n");
                    kkproc_exit(0);
                    return 0;
                }

                LOG_DBG("Received pid %d\n", GDB_SERVER_PID);
                GDB_SERVER_PORT = gdb_port;
                //ps4gdb_sys_write(client,&GDB_SERVER_PORT,4);
                ps4gdb_sys_close(client);
                if(ptrace_attach(GDB_SERVER_PID) != 0){
                    LOG_ERROR("Attaching to pid failed %d\n",errno);
                    return 0;
                }
                int stat = 0;
                ps4gdb_sys_wait4(GDB_SERVER_PID,&stat,WUNTRACED,0);
                handle_exception(0x01, NULL, 0);
            }
            ps4gdb_sys_close(client);
        }
	}
	return 0;
}

int gdb_start_server(int port, int PID)
{
    LOG_DBG("gdb_start_server\n");

    // Prepare socket
	int r = ps4gdb_sys_socket(AF_INET,SOCK_STREAM,0);
	int client = 0;

	LOG_DBG("sys_socket: 0x%llx\n",r);

	if(r > 0)
	{
		int s = r;
        r = ps4gdb_sys_bind(s,port);

		LOG_DBG("sys_bind: 0x%llx\n",r);
		if(r == 0)
		{
			r = ps4gdb_sys_listen(s, 10);

			if(r == 0)
			{
                gdb_server_setup = 1;
				int r = ps4gdb_sys_accept(s,(struct sockaddr *)NULL,0);

				LOG_DBG("sys_accept: 0x%llx\n",r);

				if(r > 0)
				{
					client = r;
					LOG_DBG("Client socket fd: 0x%llx\n",client);
                    ps4gdb_sys_shutdown(s,SHUT_RDWR);
                    ps4gdb_sys_close(s);
					return client;
				} else {
                    LOG_ERROR("Accept failed, killing proc to prevent kpanic\n");
                    kkill_t(curproc->p_pid, SIGQUIT, curthread);
                    return -1;
                }
			}
		} else {
            LOG_ERROR("Bind failed, killing proc to prevent kpanic\n");
            kkill_t(curproc->p_pid, SIGQUIT, curthread);
        }
	}

	return r;
}


code:
extern "C"
{
	#include <sys/ptrace.h>
}

#include "syscalls.hpp"
#include "log.h"

int ptrace_attach(int pid){
    return ps4gdb_sys_ptrace(PT_ATTACH,pid,0,0);
}

int ptrace_detach(int pid){
    return ps4gdb_sys_ptrace(PT_DETACH,pid,(void*)SIGCONT,0);
}

int ptrace_continue(int pid){
	return ps4gdb_sys_ptrace(PT_CONTINUE,pid,(void*)1,0);
}

int ptrace_get_regs(int pid, void *addr){
	return ps4gdb_sys_ptrace(PT_GETREGS, pid, addr, 0);
}

int ptrace_set_regs(int pid, void *addr){
	return ps4gdb_sys_ptrace(PT_SETREGS, pid, addr, 0);
}

int ptrace_step(int pid){
	return ps4gdb_sys_ptrace(PT_STEP, pid, (void *)1, 0);
}

int ptrace_suspend(int pid){
	return ps4gdb_sys_ptrace(PT_SUSPEND, pid,(void*)0, 0);
}

int ptrace_resume(int pid){
	return ps4gdb_sys_ptrace(PT_RESUME, pid,(void*)1, 0);
}

int ptrace_setstep(int pid){
	return ps4gdb_sys_ptrace(PT_SETSTEP, pid,(void*)0, 0);
}

int ptrace_clearstep(int pid){
	return ps4gdb_sys_ptrace(PT_CLEARSTEP, pid,(void*)0, 0);
}

void *ptrace_io(int pid, int op, void *off, void *addr, unsigned long long len){
	struct ptrace_io_desc io_desc;
	unsigned long long ret;

	io_desc.piod_op = op;
	io_desc.piod_offs = off;
	io_desc.piod_addr = addr;
	io_desc.piod_len = len;
	ret = ps4gdb_sys_ptrace(PT_IO, pid, (void*)&io_desc, 0);

    if(ret == 0){
		return (void*)0;
	}
	else{
		return (void*)-1;
	}
}


code:
extern "C"
{
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/_timespec.h>
#include <sys/resource.h>
#include <sys/ptrace.h>
}

int ptrace_attach(int pid);
int ptrace_detach(int pid);
int ptrace_continue(int pid);
int ptrace_get_regs(int pid, void *addr);
int ptrace_set_regs(int pid, void *addr);int ptrace_step(int pid);
int ptrace_suspend(int pid);
int ptrace_resume(int pid);
int ptrace_io(int pid, int op, void *off, void *addr, unsigned long long len);
int ptrace_setstep(int pid);
int ptrace_clearstep(int pid);


code:
extern "C"
{
    #include <sys/param.h>
    #include <sys/types.h>
    #include <sys/stdint.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/mman.h>
    #include <sys/user.h>
    #include <sys/wait.h>
    #include <sys/errno.h>
    #include "log.h"
}

#include "syscalls.hpp"
#include "ptrace.hpp"

int errno;
int GDB_SERVER_PORT;
int GDB_SERVER_PID;
int GDB_SERVER_SETUP = 0;

void handle_exception (int gdb_i386vector, unsigned long long *registersOld, int errorCode);

uint8_t *get_process_list(uint64_t *len){

    *len = 0;
    int mib[3];

	mib[0] = 1;
	mib[1] = 14;
	mib[2] = 8;

    if(ps4gdb_sys_sysctl(mib,3,NULL,len,NULL,0) < 0){
        LOG_ERROR("sysctl returned %d\n",errno);
        return NULL;
    }

    uint8_t *proc_list = (uint8_t *)ps4gdb_sys_mmap(NULL,*len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
    if(ps4gdb_sys_sysctl(mib,3,proc_list,len,NULL,0) < 0){
        LOG_ERROR("sysctl returned %d\n",errno);
        ps4gdb_sys_munmap(proc_list,*len);
        return NULL;
    }

    return proc_list;
}

int gdb_start_rpc_server(int cmd_port, int gdb_port){
    LOG_DBG("Starting server...\n");
    GDB_SERVER_PORT = gdb_port;

    int server_socket = ps4gdb_sys_socket(AF_INET, SOCK_STREAM, 0);
    if(server_socket < 0){
        LOG_DBG("Failed to create server socket. errno: %d\n",errno);
        return server_socket;
    }

    int r = ps4gdb_sys_bind(server_socket,cmd_port);
	if(r != 0){
		LOG_ERROR("sys_bind failed. errno: %d\n",errno);
		return -1;
	}

	// Preparing to listen
	LOG_DBG("Starting to listen...\n");
	r = ps4gdb_sys_listen(server_socket, 10);
	if(r != 0){
		LOG_ERROR("sys_listen returned %d\n",errno);
		return -1;
	}

	for(;;){
		// Accept connections
		LOG_DBG("Accepting connections...\n");
		int client = ps4gdb_sys_accept(server_socket,(struct sockaddr *)NULL,0);
		if(client == -1){
            LOG_ERROR("sys_accept. errno %d\n",errno);
			ps4gdb_sys_shutdown(server_socket,SHUT_RDWR);
			ps4gdb_sys_close(server_socket);
			return -1;
		} else {
            LOG_DBG("Got connection...\n");
            LOG_DBG("Socket: %d...\n", client);
            uint64_t dataLen = 0;
            struct kinfo_proc *kipp = (struct kinfo_proc *)get_process_list(&dataLen);
            LOG_DBG("kproc_info data len: %d\n");
            if(ps4gdb_sys_write(client,&dataLen,8) != -1)
            {
                LOG_DBG("Written data len\n");
                if(ps4gdb_sys_write(client,kipp,dataLen) != -1)
                {
                    LOG_DBG("Written proc info\n");
                    ps4gdb_sys_munmap(kipp,dataLen);

                    // Read PID to attach
                    ps4gdb_sys_read(client,&GDB_SERVER_PID,4);

                    if(GDB_SERVER_PID != -1)
                    {
                        if(GDB_SERVER_PID == -2){
                            LOG_DBG("Received command -2, destroying thread...\n");
                            return 0;
                        }

                        LOG_DBG("Received pid %d\n", GDB_SERVER_PID);
                        GDB_SERVER_PORT = gdb_port;
                        //ps4gdb_sys_write(client,&GDB_SERVER_PORT,4);
                        ps4gdb_sys_close(client);
                        if(ptrace_attach(GDB_SERVER_PID) != 0){
                            LOG_ERROR("Attaching to pid failed %d\n",errno);
                            return 0;
                        }
                        int stat = 0;
                        ps4gdb_sys_wait4(GDB_SERVER_PID,&stat,WUNTRACED,0);
                        handle_exception(0x01, NULL, 0);
                    } else {
                        LOG_DBG("Sending kproc_info only\n");
                    }
                } else {
                    LOG_ERROR("Could not write kproc_info\n");
                }
            } else {
                LOG_ERROR("Could not write dataLen\n");
            }
            ps4gdb_sys_close(client);
        }
	}
	return 0;
}


code:
extern "C"
{
	#include <sys/param.h>
	#include <sys/types.h>
	#include <sys/filedesc.h>
	#include <sys/stdint.h>
	#include <sys/fcntl.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <sys/mman.h>
	#include <sys/unistd.h>
	#include <vm/vm.h>
	#include <sys/malloc.h>
	#include <sys/errno.h>
	#include <sys/sx.h>
	#include <sys/sysproto.h>
	#include <sys/proc.h>
}

#include "kdl.h"
#include "log.h"
#include <Utils/Kdlsym.hpp>
#include <Utils/SysWrappers.hpp>

void ps4gdb_sys_memset(void *buff, uint8_t value, int len)
{
	uint8_t *tmp = (uint8_t*)buff;

	int i = 0;
	for(i = 0; i < len; i++)
		tmp[i] = value;

	return;
}

int ps4gdb_sys_socket(int domain, int type, int protocol){
	return ksocket_t(domain, type, protocol, curthread);
}

int ps4gdb_sys_bind(int s, int port){
	PS4GDB_kbzero();

	struct sockaddr_in sockadr;
	kbzero(&sockadr, sizeof(sockadr));
	sockadr.sin_family = AF_INET;
	sockadr.sin_port = htons(port);
	sockadr.sin_addr.s_addr = INADDR_ANY;

	return kbind_t(s, (sockaddr*)&sockadr, sizeof(sockadr), curthread);
}

int ps4gdb_sys_bindt(int s, int port, struct thread *td){
	PS4GDB_kbzero();

	struct sockaddr_in sockadr;
	kbzero(&sockadr, sizeof(sockadr));
	sockadr.sin_family = AF_INET;
	sockadr.sin_port = htons(port);
	sockadr.sin_addr.s_addr = INADDR_ANY;

	return kbind_t(s, (sockaddr*)&sockadr, sizeof(sockadr), td);
}

int ps4gdb_sys_listen(int s, int backlog){
	return klisten_t(s, backlog, curthread);
}

int ps4gdb_sys_accept(int s, struct sockaddr *name, int namelen){
	return kaccept_t(s, name, (size_t*)&namelen, curthread);
}

int ps4gdb_sys_shutdown(int fd, int how){
	return kshutdown_t(fd, how, curthread);
}

int ps4gdb_sys_close(int fd){
	kclose_t(fd, curthread);
	return 0;
}

int ps4gdb_sys_read(int fd, void *addr, size_t len){
	return kread_t(fd, addr, len, curthread);
}

void* ps4gdb_sys_mmap(void *addr, size_t len, int prot, int flags, int fd, uint64_t pos){
	return kmmap_t((caddr_t)addr, len, prot, flags, fd, pos, curthread);
}

void* ps4gdb_sys_munmap(void *addr, size_t len){
	kmunmap_t((caddr_t)addr, len, curthread);
	return (void*)0;

}

int ps4gdb_sys_write(int fd, void *addr, int len){
	return kwrite_t(fd, addr, len, curthread);
}

int ps4gdb_sys_open(char *path, int flags, int mode){
	return kopen_t(path, mode, flags, curthread);
}

int ps4gdb_sys_getpid(){
	PS4GDB_ksys_getpid();

	struct thread *td = curthread;
	td->td_retval[0] = 0;
	ksys_getpid(td);
	return td->td_retval[0];
}

int ps4gdb_sys_ptrace(int req, pid_t pid, void *addr, int data){
	return kptrace_t(req, pid, (caddr_t)addr, data, curthread);
}

int ps4gdb_sys_wait4(int wpid, int *status, int	options, void *rusage2){
	return kwait4_t(wpid, status, options, (rusage*)rusage2, curthread);
}

int ps4gdb_sys_sysctl(int *name, uint32_t namelen, void *old, size_t *oldlenp, void *newaddr, size_t newlen){
    PS4GDB_ksys_sysctl();
	PS4GDB_kmalloc();
	PS4GDB_kfree();
	PS4GDB_kM_TEMP();

    // alloc and prepare uap
	struct ps4gdb_sys_gen_uap *uap = (struct ps4gdb_sys_gen_uap*)kmalloc(sizeof(struct ps4gdb_sys_gen_uap),kM_TEMP,0x102);
	ps4gdb_sys_memset(uap,0x00, sizeof(struct ps4gdb_sys_gen_uap));
    uap->p1 = (uint64_t)name;
	uap->p2 = (uint64_t)namelen;
    uap->p3 = (uint64_t)old;
	uap->p4 = (uint64_t)oldlenp;
    uap->p5 = (uint64_t)newaddr;
	uap->p6 = (uint64_t)newlen;

	struct thread *td = curthread;
	td->td_retval[0] = 0;

	int error = ksys_sysctl(td,uap);
	kfree((void*)uap,kM_TEMP);

	if(error){
		LOG_ERROR("sys_sysctl returned %d\n",error);
		td->td_retval[0] = -1;
	}

	return td->td_retval[0];
}


code:
extern "C"
{
    #include <sys/param.h>
    #include <sys/types.h>
    #include <sys/stdint.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/_timespec.h>
    #include <sys/resource.h>
}

int ps4gdb_sys_socket(int domain, int type, int protocol);
int ps4gdb_sys_bind(int s, int port);
int ps4gdb_sys_listen(int s, int backlog);
int ps4gdb_sys_accept(int s, struct sockaddr *name, int namelen);
int ps4gdb_sys_close(int fd);
int ps4gdb_sys_read(int fd, void *addr, size_t len);
int ps4gdb_sys_write(int fd, void *addr, int len);
int ps4gdb_sys_getdents(int fd, void *addr, int len);
int ps4gdb_sys_open(char *path, int flags, int mode);
int ps4gdb_sys_getpid();
void *ps4gdb_sys_mmap(void *addr, size_t len, int prot, int flags, int fd, uint64_t pos);
int ps4gdb_sys_munmap(void *addr, size_t len);
int ps4gdb_sys_shutdown(int fd, int how);
int ps4gdb_sys_mkdir(char *path, int mode);
int ps4gdb_sys_rmdir(char *path);
int ps4gdb_sys_stat(const	char * restrictpath, void *sb);
int ps4gdb_sys_ptrace(int req, pid_t pid, void *addr, int data);
int ps4gdb_sys_wait4(int wpid, int *status, int	options, void *rusage);
int ps4gdb_sys_sysctl(int *name, uint32_t namelen, void *old, size_t *oldlenp, void *newaddr, size_t newlen);


code:
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "PluginManager.hpp"

// Built in plugins
#include <Plugins/Debugger/Debugger2.hpp>
#include <Plugins/LogServer/LogManager.hpp>
#include <Plugins/FileManager/FileManager.hpp>
#include <Plugins/FakeSelf/FakeSelfManager.hpp>
#include <Plugins/FakePkg/FakePkgManager.hpp>
#include <Plugins/Substitute/Substitute.hpp>
#include <Plugins/BrowserActivator/BrowserActivator.hpp>
#include <Plugins/MorpheusEnabler/MorpheusEnabler.hpp>
#include <Plugins/RemotePlayEnabler/RemotePlayEnabler.hpp>
#include <Plugins/SyscallGuard/SyscallGuardPlugin.hpp>
#include <Plugins/TTYRedirector/TTYRedirector.hpp>
#include <Plugins/ModuleLoader/ModuleLoader.hpp>
#include <Plugins/PS4GDB/PS4GDB.hpp>
#include <Plugins/RING0GDB/RING0GDB.hpp>

// Utility functions
#include <Utils/Logger.hpp>
#include <Utils/Span.hpp>

extern "C"
{
    #include <sys/syslimits.h>
};

using namespace Mira::Plugins;

PluginManager::PluginManager() :
	m_Logger(nullptr),
    m_Debugger(nullptr),
    m_FileManager(nullptr),
    m_FakeSelfManager(nullptr),
    m_FakePkgManager(nullptr),
    m_EmuRegistry(nullptr),
    m_Substitute(nullptr),
    m_BrowserActivator(nullptr),
    m_MorpheusEnabler(nullptr),
    m_RemotePlayEnabler(nullptr),
    m_SyscallGuard(nullptr),
    m_TTYRedirector(nullptr)
{
    // Hushes error: private field 'm_FileManager' is not used [-Werror,-Wunused-private-field]
	m_Logger = nullptr;
    m_FileManager = nullptr;
	m_PS4GDB = nullptr;
	m_ModuleLoader = nullptr;
    m_RING0GDB = nullptr;
}

PluginManager::~PluginManager()
{
}

bool PluginManager::OnLoad()
{
    WriteLog(LL_Debug, "loading all plugins");

    bool s_Success = true;
    do
    {
        // Initialize debugger
        m_Debugger = new Mira::Plugins::Debugger2();
        if (m_Debugger == nullptr)
        {
            WriteLog(LL_Error, "could not allocate debugger.");
            s_Success = false;
            break;
        }

        // Initialize the syscall guard
        /*m_SyscallGuard = new Mira::Plugins::SyscallGuard();
        if (m_SyscallGuard == nullptr)
        {
            WriteLog(LL_Error, "could not allocate syscall guard.");
            s_Success = false;
            break;
        }
        if (!m_SyscallGuard->OnLoad())
            WriteLog(LL_Error, "could not load syscall guard.");*/

        // Initialize Logger
        m_Logger = new Mira::Plugins::LogManagerExtent::LogManager();
        if (m_Logger == nullptr)
        {
            WriteLog(LL_Error, "could not allocate log manager.");
            return false;
        }
        if (!m_Logger->OnLoad())
            WriteLog(LL_Error, "could not load logmanager");

        // Initialize file manager
        m_FileManager = new Mira::Plugins::FileManagerExtent::FileManager();
        if (m_FileManager == nullptr)
        {
            WriteLog(LL_Error, "could not allocate file manager.");
            s_Success = false;
            break;
        }

        // Initialize the fself manager
        m_FakeSelfManager = new Mira::Plugins::FakeSelfManager();
        if (m_FakeSelfManager == nullptr)
        {
            WriteLog(LL_Error, "could not allocate fake self manager.");
            s_Success = false;
            break;
        }

        // Initialize the fpkg manager
        m_FakePkgManager = new Mira::Plugins::FakePkgManager();
        if (m_FakePkgManager == nullptr)
        {
            WriteLog(LL_Error, "could not allocate fake pkg manager.");
            s_Success = false;
            break;
        }

        // Initialize Substitute
        m_Substitute = new Mira::Plugins::Substitute();
        if (m_Substitute == nullptr)
        {
            WriteLog(LL_Error, "could not allocate substitute.");
            s_Success = false;
            break;
        }

        // Initialize BrowserActivator
        m_BrowserActivator = new Mira::Plugins::BrowserActivator();
        if (m_BrowserActivator == nullptr)
        {
            WriteLog(LL_Error, "could not allocate browser activator.");
            s_Success = false;
            break;
        }

        // Initialize MorpheusEnabler
        m_MorpheusEnabler = new Mira::Plugins::MorpheusEnabler();
        if (m_MorpheusEnabler == nullptr)
        {
            WriteLog(LL_Error, "could not allocate morpheus enabler.");
            s_Success = false;
            break;
        }

        // Initialize RemotePlayEnabler
        m_RemotePlayEnabler = new Mira::Plugins::RemotePlayEnabler();
        if (m_RemotePlayEnabler == nullptr)
        {
            WriteLog(LL_Error, "could not allocate remote play enabler.");
            s_Success = false;
            break;
        }

        // Initialize TTYRedirector
        m_TTYRedirector = new Mira::Plugins::TTYRedirector();
        if (m_TTYRedirector == nullptr)
        {
            WriteLog(LL_Error, "could not allocate tty redirector.");
            s_Success = false;
            break;
        }

		// Initialize PS4GDB
		m_PS4GDB = new Mira::Plugins::PS4GDB();
        if (m_PS4GDB == nullptr)
        {
            WriteLog(LL_Error, "could not allocate PS4GDB.");
            s_Success = false;
            break;
        }

		// Initialize ModuleLoader
        m_ModuleLoader = new Mira::Plugins::ModuleLoader();
        if (m_ModuleLoader == nullptr)
        {
            WriteLog(LL_Error, "could not allocate ModuleLoader.");
            s_Success = false;
            break;
        }

        // Initialize RING0GDB
        m_RING0GDB = new Mira::Plugins::RING0GDB();
        if (m_RING0GDB == nullptr)
        {
            WriteLog(LL_Error, "could not allocate RING0GDB.");
            s_Success = false;
            break;
        }
    } while (false);

    if (m_Debugger)
    {
        if (!m_Debugger->OnLoad())
            WriteLog(LL_Error, "could not load debugger.");
    }

    if (m_FileManager)
    {
        if (!m_FileManager->OnLoad())
            WriteLog(LL_Error, "could not load filemanager");
    }

    if (m_FakeSelfManager)
    {
        if (!m_FakeSelfManager->OnLoad())
            WriteLog(LL_Error, "could not load fake self manager.");
    }

    if (m_FakePkgManager)
    {
        if (!m_FakePkgManager->OnLoad())
            WriteLog(LL_Error, "could not load fake pkg manager.");
    }

    if (m_EmuRegistry)
    {
        if (!m_EmuRegistry->OnLoad())
            WriteLog(LL_Error, "could not load emulated registry.");
    }

    if (m_Substitute)
    {
        if (!m_Substitute->OnLoad())
            WriteLog(LL_Error, "could not load substitute.");
    }

    if (m_BrowserActivator)
    {
        if (!m_BrowserActivator->OnLoad())
            WriteLog(LL_Error, "could not load browser activator.");
    }

    if (m_MorpheusEnabler)
    {
        if (!m_MorpheusEnabler->OnLoad())
            WriteLog(LL_Error, "could not load morpheus enabler.");
    }

    if (m_RemotePlayEnabler)
    {
        if (!m_RemotePlayEnabler->OnLoad())
            WriteLog(LL_Error, "could not load remote play enabler.");
    }

    if (m_TTYRedirector)
    {
        if (!m_TTYRedirector->OnLoad())
            WriteLog(LL_Error, "could not load tty redirector.");
    }

	if (m_PS4GDB)
    {
        if (!m_PS4GDB->OnLoad())
            WriteLog(LL_Error, "could not load PS4GDB.");
    }

	if (m_ModuleLoader)
    {
        if (!m_ModuleLoader->OnLoad())
            WriteLog(LL_Error, "could not load ModuleLoader.");
    }

    if(m_RING0GDB)
    {
        if (!m_RING0GDB->OnLoad())
            WriteLog(LL_Error, "could not load RING0GDB.");
    }

    return s_Success;
}

bool PluginManager::OnUnload()
{
    WriteLog(LL_Debug, "unloading all plugins");
    bool s_AllUnloadSuccess = true;

    for (auto i = 0; i < m_Plugins.size(); ++i)
    {
        WriteLog(LL_Debug, "unloading plugin idx: (%d).", i);
        auto l_Plugin = m_Plugins[i];

        // Skip any blank spots
        if (l_Plugin == nullptr)
            continue;

        WriteLog(LL_Debug, "unloading plugin: (%s).", l_Plugin->GetName());
        // TODO: Handle multiple unloads
        auto s_UnloadResult = l_Plugin->OnUnload();
        if (!s_UnloadResult)
            s_AllUnloadSuccess = false;

        WriteLog(LL_Info, "plugin (%s) unloaded %s",
            l_Plugin->GetName(), s_UnloadResult ? "successfully" : "unsuccessfully");

        WriteLog(LL_Debug, "freeing plugin");
        // Delete the plugin
        delete l_Plugin;

        WriteLog(LL_Debug, "clearing entry");
        m_Plugins[i] = nullptr;
    }

    WriteLog(LL_Debug, "clearing array");
    // Clear out all entries
    m_Plugins.clear();

    // Free the default plugins
    // Delete the file manager
    if (m_FileManager)
    {
        WriteLog(LL_Debug, "unloading file manager");

        if (!m_FileManager->OnUnload())
            WriteLog(LL_Error, "filemanager could not unload");

        // Free the file manager
        delete m_FileManager;
        m_FileManager = nullptr;
    }

    // Delete the fake self manager
    if (m_FakeSelfManager)
    {
        WriteLog(LL_Debug, "unloading fake self manager");
        if (!m_FakeSelfManager->OnUnload())
            WriteLog(LL_Error, "fake self manager could not unload");

        delete m_FakeSelfManager;
        m_FakeSelfManager = nullptr;
    }

    // Delete the fake pkg manager
    if (m_FakePkgManager)
    {
        WriteLog(LL_Debug, "unloading fake pkg manager");
        if (!m_FakePkgManager->OnUnload())
            WriteLog(LL_Error, "fake pkg manager could not unload");

        delete m_FakePkgManager;
        m_FakePkgManager = nullptr;
    }

    // Delete the emulated registry
    if (m_EmuRegistry)
    {
        WriteLog(LL_Debug, "unloading emulated registry");
        if (!m_EmuRegistry->OnUnload())
            WriteLog(LL_Error, "emuRegistry could not unload");

        delete m_EmuRegistry;
        m_EmuRegistry = nullptr;
    }

    if (m_SyscallGuard)
    {
        WriteLog(LL_Debug, "unloading syscall guard");
        if (!m_SyscallGuard->OnUnload())
            WriteLog(LL_Error, "syscall guard could not unload");

        delete m_SyscallGuard;
        m_SyscallGuard = nullptr;
    }

    // Delete the log server
    if (m_Logger)
    {
        WriteLog(LL_Debug, "unloading log manager");

        if (!m_Logger->OnUnload())
            WriteLog(LL_Error, "logmanager could not unload");

        // Free the file manager
        delete m_Logger;
        m_Logger = nullptr;
    }

    // Delete Substitute
    if (m_Substitute)
    {
        WriteLog(LL_Debug, "unloading substitute");
        if (!m_Substitute->OnUnload())
            WriteLog(LL_Error, "substitute could not unload");

        // Free Substitute
        delete m_Substitute;
        m_Substitute = nullptr;
    }

    // Delete BrowserActivator
    if (m_BrowserActivator)
    {
        WriteLog(LL_Debug, "unloading browser activator");
        if (!m_BrowserActivator->OnUnload())
            WriteLog(LL_Error, "browser activator could not unload");

        // Free BrowserActivator
        delete m_BrowserActivator;
        m_BrowserActivator = nullptr;
    }

    // Delete MorpheusEnabler
    if (m_MorpheusEnabler)
    {
        WriteLog(LL_Debug, "unloading morpheus enabler");
        if (!m_MorpheusEnabler->OnUnload())
            WriteLog(LL_Error, "morpheus enabler could not unload");

        // Free MorpheusEnabler
        delete m_MorpheusEnabler;
        m_MorpheusEnabler = nullptr;
    }

    // Delete RemotePlayEnabler
    if (m_RemotePlayEnabler)
    {
        WriteLog(LL_Debug, "unloading remote play enabler");
        if (!m_RemotePlayEnabler->OnUnload())
            WriteLog(LL_Error, "remote play enabler could not unload");

        // Free RemotePlayEnabler
        delete m_RemotePlayEnabler;
        m_RemotePlayEnabler = nullptr;
    }

    // Delete the debugger
    // NOTE: Don't unload before the debugger for catch error if something wrong
    if (m_Debugger)
    {
        WriteLog(LL_Debug, "unloading debugger");
        if (!m_Debugger->OnUnload())
            WriteLog(LL_Error, "debugger could not unload");

        // Free the debugger
        delete m_Debugger;
        m_Debugger = nullptr;
    }

    // Unload TTY Redirector
    if (m_TTYRedirector)
    {
        WriteLog(LL_Debug, "unloading tty redirector");
        if (!m_TTYRedirector->OnUnload())
            WriteLog(LL_Error, "tty redirector could not unload");

        // Free TTYRedirector
        delete m_TTYRedirector;
        m_TTYRedirector = nullptr;
    }

    WriteLog(LL_Debug, "All Plugins Unloaded %s.", s_AllUnloadSuccess ? "successfully" : "un-successfully");
    return s_AllUnloadSuccess;
}

bool PluginManager::OnSuspend()
{
    // Hold our "all success" status
    bool s_AllSuccess = true;

    // Iterate through all of the plugins
    for (auto i = 0; i < m_Plugins.size(); ++i)
    {
        // Validate that this plugin still exists
        auto l_Plugin = m_Plugins[i];
        if (l_Plugin == nullptr)
            continue;

        // Suspend the plugin
        auto s_SuspendResult = l_Plugin->OnSuspend();
        if (!s_SuspendResult)
            s_AllSuccess = false;

        // Debugging status
        WriteLog(LL_Info, "plugin (%s) suspend %s",
            l_Plugin->GetName(),
            s_SuspendResult ? "success" : "failure");
    }

    // Suspend the built in plugins
    if (m_FileManager)
    {
        if (!m_FileManager->OnSuspend())
            WriteLog(LL_Error, "file manager suspend failed");
    }

    if (m_FakeSelfManager)
    {
        if (!m_FakeSelfManager->OnSuspend())
            WriteLog(LL_Error, "fake self manager suspend failed");
    }

    if (m_EmuRegistry)
    {
        if (!m_EmuRegistry->OnSuspend())
            WriteLog(LL_Error, "emuRegistry suspend failed");
    }

    // Suspend both of the loggers (cleans up the sockets)
    if (m_Logger)
    {
        if (!m_Logger->OnSuspend())
            WriteLog(LL_Error, "log manager suspend failed");
    }

    // Suspend substitute (currently does nothing)
    if (m_Substitute)
    {
        if (!m_Substitute->OnSuspend())
            WriteLog(LL_Error, "substitute suspend failed");
    }

    // Suspend BrowserActivator (does nothing)
    if (m_BrowserActivator)
    {
        if (!m_BrowserActivator->OnSuspend())
            WriteLog(LL_Error, "browser activator suspend failed");
    }

    // Suspend MorpheusEnabler (does nothing)
    if (m_MorpheusEnabler)
    {
        if (!m_MorpheusEnabler->OnSuspend())
            WriteLog(LL_Error, "morpheus enabler suspend failed");
    }

    // Suspend RemotePlayEnabler (does nothing)
    if (m_RemotePlayEnabler)
    {
        if (!m_RemotePlayEnabler->OnSuspend())
            WriteLog(LL_Error, "remote play enabler suspend failed");
    }

    // Nota: Don't suspend before the debugger for catch error if something when wrong
    if (m_Debugger)
    {
        if (!m_Debugger->OnSuspend())
            WriteLog(LL_Error, "debugger suspend failed");
    }

    // Suspend TTYRedirector (does nothing)
    if (m_TTYRedirector)
    {
        if (!m_TTYRedirector->OnSuspend())
            WriteLog(LL_Error, "tty redirector suspend failed");
    }

    // Return final status
    return s_AllSuccess;
}

bool PluginManager::OnResume()
{
    // Hold our "all success" status
    bool s_AllSuccess = true;

    WriteLog(LL_Debug, "Resuming all plugins");

    WriteLog(LL_Debug, "resuming debugger");
    if (m_Debugger)
    {
        if (!m_Debugger->OnResume())
            WriteLog(LL_Error, "debugger resume failed");
    }

    WriteLog(LL_Debug, "resuming log manager");
    if (m_Logger)
    {
        if (!m_Logger->OnResume())
            WriteLog(LL_Error, "log manager resume failed");
    }

    WriteLog(LL_Debug, "resuming emuRegistry");
    if (m_EmuRegistry)
    {
        if (!m_EmuRegistry->OnResume())
            WriteLog(LL_Error, "emuRegistry resume failed");
    }

    WriteLog(LL_Debug, "resuming substitute");
    if (m_Substitute)
    {
        if (!m_Substitute->OnResume())
            WriteLog(LL_Error, "substitute resume failed");
    }

    WriteLog(LL_Debug, "resuming browser activator");
    if (m_BrowserActivator)
    {
        if (!m_BrowserActivator->OnResume())
            WriteLog(LL_Error, "browser activator resume failed");
    }

    WriteLog(LL_Debug, "resuming morpheus enabler");
    if (m_MorpheusEnabler)
    {
        if (!m_MorpheusEnabler->OnResume())
            WriteLog(LL_Error, "morpheus enabler resume failed");
    }

    WriteLog(LL_Debug, "resuming remote play enabler");
    if (m_RemotePlayEnabler)
    {
        if (!m_RemotePlayEnabler->OnResume())
            WriteLog(LL_Error, "remote play enabler resume failed");
    }

    WriteLog(LL_Debug, "resuming tty redirector");
    if (m_TTYRedirector)
    {
        if (!m_TTYRedirector->OnResume())
            WriteLog(LL_Error, "tty redirector resume failed");
    }

	if (m_ModuleLoader)
    {
        if (!m_ModuleLoader->OnResume())
            WriteLog(LL_Error, "could not Resume ModuleLoader.");
    }

    if (m_PS4GDB)
    {
        if (!m_PS4GDB->OnResume())
            WriteLog(LL_Error, "could not Resume PS4GDB.");
    }

    // Iterate through all of the plugins
    for (auto i = 0; i < m_Plugins.size(); ++i)
    {
        // Validate that this plugin still exists
        WriteLog(LL_Error, "Resuming plugin idx: (%d).", i);
        auto l_Plugin = m_Plugins[i];
        if (l_Plugin == nullptr)
            continue;

        // Resume the plugin
        WriteLog(LL_Info, "resuming plugin (%s).", l_Plugin->GetName());
        auto s_ResumeResult = l_Plugin->OnResume();
        if (!s_ResumeResult)
            s_AllSuccess = false;

        // Debugging status
        WriteLog(LL_Info, "plugin (%s) resume %s",
            l_Plugin->GetName(),
            s_ResumeResult ? "success" : "failure");
    }

    WriteLog(LL_Debug, "resuming file manager");
    if (m_FileManager)
    {
        if (!m_FileManager->OnResume())
            WriteLog(LL_Error, "file manager resume failed");
    }

    WriteLog(LL_Debug, "resuming fake self manager");
    if (m_FakeSelfManager)
    {
        if (!m_FakeSelfManager->OnResume())
            WriteLog(LL_Error, "fake self manager resume failed");
    }

    WriteLog(LL_Debug, "resume all %s", s_AllSuccess ? "successfully" : "un-successfully");

    // Return final status
    return s_AllSuccess;
}

bool PluginManager::OnProcessExec(struct proc* p_Process)
{
    if (p_Process == nullptr)
        return false;

    if (m_Substitute)
    {
        if (!m_Substitute->OnProcessExec(p_Process))
            WriteLog(LL_Error, "substitute process exec failed.");
    }

    if (m_Debugger)
    {
        if (!m_Debugger->OnProcessExec(p_Process))
            WriteLog(LL_Error, "debugger process exec failed.");
    }

    return true;
}

bool PluginManager::OnProcessExecEnd(struct proc* p_Process)
{
    if (p_Process == nullptr)
        return false;

    if (m_Substitute)
    {
        if (!m_Substitute->OnProcessExecEnd(p_Process))
            WriteLog(LL_Error, "substitute process exec end failed.");
    }

    return true;
}

bool PluginManager::OnProcessExit(struct proc* p_Process)
{
    if (p_Process == nullptr)
        return false;

    if (m_Substitute)
    {
        if (!m_Substitute->OnProcessExit(p_Process))
            WriteLog(LL_Error, "substitute process exit failed.");
    }

    if (m_Debugger)
    {
        if (!m_Debugger->OnProcessExit(p_Process))
            WriteLog(LL_Error, "debugger process exit failed.");
    }

    return true;
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Vector.hpp>

extern "C"
{
    #include <sys/param.h>
    #include <sys/mutex.h>
}

namespace Mira
{
    namespace Plugins
    {
        class PluginManager : public Mira::Utils::IModule
        {
        private:
            Vector<Mira::Utils::IModule*> m_Plugins;

        public:
            PluginManager();
            virtual ~PluginManager();

            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

            virtual bool OnProcessExec(struct proc* p_Process) override;
            virtual bool OnProcessExecEnd(struct proc* p_Process) override;
            virtual bool OnProcessExit(struct proc* p_Process) override;

        private:
            Mira::Utils::IModule* m_Logger;
            Mira::Utils::IModule* m_Debugger;
            Mira::Utils::IModule* m_FileManager;
            Mira::Utils::IModule* m_FakeSelfManager;
            Mira::Utils::IModule* m_FakePkgManager;
            Mira::Utils::IModule* m_EmuRegistry;
            Mira::Utils::IModule* m_Substitute;
            Mira::Utils::IModule* m_BrowserActivator;
            Mira::Utils::IModule* m_MorpheusEnabler;
            Mira::Utils::IModule* m_RemotePlayEnabler;
            Mira::Utils::IModule* m_SyscallGuard;
            Mira::Utils::IModule* m_TTYRedirector;
			Mira::Utils::IModule* m_PS4GDB;
			Mira::Utils::IModule* m_ModuleLoader;
            Mira::Utils::IModule* m_RING0GDB;

        public:
            Mira::Utils::IModule* GetDebugger() { return m_Debugger; }
            Mira::Utils::IModule* GetFakeSelfManager() { return m_FakeSelfManager; }
            Mira::Utils::IModule* GetEmulatedRegistry() { return m_EmuRegistry; }
            Mira::Utils::IModule* GetSubstitute() { return m_Substitute; }
            Mira::Utils::IModule* GetBrowserActivator() { return m_BrowserActivator; }
            Mira::Utils::IModule* GetMorpheusEnabler() { return m_MorpheusEnabler; }
            Mira::Utils::IModule* GetRemotePlayEnabler() { return m_RemotePlayEnabler; }
            Mira::Utils::IModule* GetSyscallGuard() { return m_SyscallGuard; }
        };
    }
}


code:
#include "RING0GDB.hpp"
#include "kdl.h"
#include "log.h"
#include "syscalls.hpp"
#include <Utils/Kdlsym.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Hook.hpp>

#include <Utils/SysWrappers.hpp>

#include <sys/param.h>
#include <sys/types.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/stdint.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/unistd.h>
#include <vm/vm.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/sx.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/sysent.h>

#include <Mira.hpp>
#include <Utils/Kdlsym.hpp>

void gdbstub_set_debug_traps (void);

using namespace Mira::Plugins;

RING0GDB::RING0GDB()
{

}

RING0GDB::~RING0GDB()
{

}

bool RING0GDB::OnLoad()
{
    return this->SpawnKproc();
}

bool RING0GDB::OnUnload()
{
    return true;
}

bool RING0GDB::OnSuspend()
{
    return OnUnload();
}

bool RING0GDB::OnResume()
{
    return this->SpawnKproc();
}

void RING0GDB::GetRoot()
{
    struct prison **prison0 = NULL;
    struct vnode **rootvnode = NULL;
    struct thread *td = curthread;

	/* Resolve credentials */
	struct ucred *cred;
	struct filedesc *fd;

	fd = td->td_proc->p_fd;
	cred = td->td_proc->p_ucred;

	/* Escalate process to uid0 */
	cred->cr_uid = 0;
	cred->cr_ruid = 0;
	cred->cr_rgid = 0;
	cred->cr_groups[0] = 0;

	/* Break out of FreeBSD jail */
	prison0 = (struct prison **)kdlsym(prison0);
	cred->cr_prison = prison0[0];

	/* Set sony auth ID flag */
	cred->cr_sceAuthID = 0x3800000000000007ULL;

	/* Obtain system credentials for Sony stuff */
	cred->cr_sceCaps[0] = 0xffffffffffffffff;
	cred->cr_sceCaps[1] = 0xffffffffffffffff;

	/* Set vnode to real root "/" to defeat sandbox */
	rootvnode = (struct vnode **)kdlsym(rootvnode);
	fd->fd_rdir = rootvnode[0];
	fd->fd_jdir = rootvnode[0];
}

bool RING0GDB::SpawnKproc()
{
	auto kproc_create = (int(*)(void (*func)(void *), void *arg, struct proc **newpp, int flags, int pages, const char *fmt, ...)) kdlsym(kproc_create);
    auto kmalloc = (void*(*)(size_t size, struct	malloc_type *type, int Flags))kdlsym(malloc);
    auto kM_TEMP = (struct	malloc_type *)kdlsym(M_TEMP);

    struct proc *p = (struct proc*)kmalloc(sizeof(struct proc), kM_TEMP, 0x102);
    WriteLog(LL_Info, "RING0GDBMain allocated at: 0x%llx", (uint64_t)p);
    WriteLog(LL_Info, "Spawing KprocMain...");
    kproc_create(RING0GDB::RING0GDBMain, NULL, &p, 0, 0, "RING0GDB");
    return true;
}

struct thread *RING0GDBMainThread;

void RING0GDB::RING0GDBMain(void *)
{
	WriteLog(LL_Info, "RING0GDB::RING0GDBMain Getting root...");
    RING0GDB::GetRoot();

    // create new vmspace
    WriteLog(LL_Info, "RING0GDB::RING0GDBMain Creating new vmspace...");
	vm_offset_t sv_minuser;
	struct vmspace *vmspace;
	struct proc *p = curproc;
	struct sysentvec *sv = (struct sysentvec *)kdlsym(self_orbis_sysvec);

    // allocate user mode virtual space
    auto kvmspace_alloc = (struct vmspace*(*)(vm_offset_t min, vm_offset_t max)) kdlsym(vmspace_alloc);
    auto kpmap_activate = (void(*)(struct thread *td)) kdlsym(pmap_activate);

	sv_minuser = MAX(sv->sv_minuser, PAGE_SIZE);
	vmspace = kvmspace_alloc(sv_minuser, sv->sv_maxuser);
	if (!vmspace)
	{
		WriteLog(LL_Error, "RING0GDB::RING0GDBMain Could not allocate new vm space\n");
		return;
	}

    // setup vmspace
    WriteLog(LL_Info, "RING0GDB::RING0GDBMain Activate vmspace...");
	p->p_vmspace = vmspace;
	if (p == curthread->td_proc)
		kpmap_activate(curthread);

    WriteLog(LL_Info, "RING0GDB::RING0GDBMain Creating stdin/out/err...\n");
    kopen_t("/dev/console", O_RDONLY,0, curthread);
    kopen_t("/dev/console", O_RDONLY,0, curthread);
    kopen_t("/dev/console", O_RDONLY,0, curthread);

	WriteLog(LL_Info, "RING0GDB::RING0GDBMain Starting server: PROTOCOL PORT 9946\n");
	//Print thread info
    struct thread *td = curthread;
    /* Resolve credentials */
	struct ucred *cred;
    cred = td->td_proc->p_ucred;
    LOG_DBG("sceAuthID: 0x%llx\n",cred->cr_sceAuthID);
    LOG_DBG("cr_sceCaps[0]: 0x%llx\n",cred->cr_sceCaps[0]);
    LOG_DBG("cr_sceCaps[1]: 0x%llx\n",cred->cr_sceCaps[1]);
    // Start server
	LOG_DBG("PID: %d\n", ps4gdb_sys_getpid());

	uint8_t idtr[10];
	cpu_sidt((struct idt*)&idtr);

	uint64_t *base = (uint64_t*)&idtr[2];
	uint16_t *limit = (uint16_t*)&idtr[0];

	LOG_DBG("kernelbase: 0x%llx\n", (uint8_t*)kernelRdmsr(0xC0000082) - kdlsym_addr_Xfast_syscall);
	LOG_DBG("idtr->base: 0x%llx\n", *base);
	LOG_DBG("idtr->limit: 0x%llx\n", *limit);

	// Setup debug traps
	RING0GDBMainThread = curthread;
	gdbstub_set_debug_traps();

	//Endlessloop here to keep the process alive
	PS4GDB_kavcontrol_sleep();
	LOG_DBG("Entering main process sleep\n");
	int kill_this_process = 0;
	while(1){
		kavcontrol_sleep(100000);
		if(kill_this_process == 1)
			break;
	}

	return;
}


code:
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Hook.hpp>
#include <Utils/Kernel.hpp>
#include <Utils/Logger.hpp>
#include <Utils/Kdlsym.hpp>
#include <Utils/SysWrappers.hpp>

#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/Rpc/Connection.hpp>
#include <Messaging/MessageManager.hpp>
#include <Plugins/PluginManager.hpp>

#include <OrbisOS/Utilities.hpp>

#include <Mira.hpp>

extern "C"
{
    #include <Messaging/Rpc/rpc.pb-c.h>

    #include <sys/uio.h>
	#include <sys/proc.h>
	#include <sys/ioccom.h>
    #include <sys/ptrace.h>
    #include <sys/mman.h>
    #include <sys/sx.h>
    #include <sys/errno.h>
    #include <sys/wait.h>
    #include <sys/socket.h>

    #include <vm/vm.h>
	#include <vm/pmap.h>

    #include <machine/reg.h>
    #include <machine/param.h>
    #include <machine/frame.h>
	#include <machine/psl.h>
	#include <machine/pmap.h>
	#include <machine/segments.h>

	#include <sys/eventhandler.h>
};

namespace Mira
{
    namespace Plugins
    {
        class RING0GDB : public Utils::IModule
        {
        public:
            RING0GDB();
            virtual ~RING0GDB();

            virtual const char* GetName() override { return "RING0GDB"; }
            virtual const char* GetDescription() override { return "PS4 kernel gdbstub"; }

            // Module callbacks
            virtual bool OnLoad() override;
            virtual bool OnUnload() override;
            virtual bool OnSuspend() override;
            virtual bool OnResume() override;

        protected:
        private:
            // Necessary methods
            static void RING0GDBMain(void *);
            bool SpawnKproc();
            static void GetRoot();
        };
    }
}


code:
.intel_syntax noprefix
.text

.global cpu_sidtRing01

cpu_sidtRing01:
  sidt [rdi]
  xor rax,rax
  ret


code:
/************************************************************
                 psfbsdk by m0rph3us1987
************************************************************/

extern "C"
{
#include <sys/param.h>
#include <sys/types.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/stdint.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <vm/vm.h>
#include <sys/malloc.h>
#include <sys/sysproto.h>
#include <sys/param.h>
#include <sys/ctype.h>
#include <sys/limits.h>
}

#include "kdl.h"
#include "log.h"
#include "syscalls.hpp"
#include <Utils/SysWrappers.hpp>

extern "C"
{
	void cpu_sidt(void*);
	void cpu_enable_wp();
	void cpu_disable_wp();
	int gdb_start_serverRing0(int port);
	extern struct thread *RING0GDBMainThread;
}

static int gdb_server_socket = -1;
int gdb_start_server(int port);

int get_gdb_server_socket(){
	return gdb_server_socket;
}

void set_gdb_server_socket(int val){
	gdb_server_socket = val;
}

int gdb_writeRing0(void *buff, int len)
{
	return kwrite_t(gdb_server_socket, buff, len, RING0GDBMainThread);
}

void gdb_close_client_socketRing0()
{
	kclose_t(gdb_server_socket, RING0GDBMainThread);
	gdb_server_socket = -1;
	return;
}

void gdb_putDebugCharRing0(unsigned char c)
{
	if(gdb_server_socket != -1)
		gdb_writeRing0(&c,1);
}

int gdb_readRing0(void *buff, int len)
{
	return kread_t(gdb_server_socket, buff, len, RING0GDBMainThread);
}

unsigned char gdb_getDebugCharRing0()
{
	unsigned char c = 0x00;

	// If no connection is available, start server
	if(gdb_server_socket == -1)
	{
		gdb_server_socket = gdb_start_serverRing0(9946);
	}

	while(gdb_readRing0(&c,1) != 1){}

	return c;
}

extern "C"
{

void gdb_exceptionHandlerRing0(int exception_number, void *exception_address)
{
	LOG_DBG("overwriting exception handler for int %d\n", exception_number);

	uint64_t funcAddrIU64 = (uint64_t)exception_address;
	uint8_t *funcAddress = (uint8_t*)&funcAddrIU64;

	// Read idrt
	uint8_t idtr[10];
	cpu_sidt((void*)&idtr);

	// Find idt begin
	uint64_t *base = (uint64_t*)&idtr[2];

	LOG_DBG("found idt at 0x%llx\n",*base);

	// Find correct entry
	uint8_t *entry = (uint8_t*)*base;
	entry += (0x10 * exception_number);

	// Getting original pointer
	uint64_t OriginalEntry = 0x00;
	uint8_t *origBytes = (uint8_t*)&OriginalEntry;
	origBytes[0] = entry[0];
	origBytes[1] = entry[1];
	origBytes[2] = entry[6];
	origBytes[3] = entry[7];
	origBytes[4] = entry[8];
	origBytes[5] = entry[9];
	origBytes[6] = entry[10];
	origBytes[7] = entry[11];

	LOG_DBG("Entry %d at 0x%llx pointing to 0x%llx\n", exception_number, entry, OriginalEntry);

	// Replace function pointer
	cpu_disable_wp();
	asm("cli");
	entry[0] = funcAddress[0];
	entry[1] = funcAddress[1];
	entry[6] = funcAddress[2];
	entry[7] = funcAddress[3];
	entry[8] = funcAddress[4];
	entry[9] = funcAddress[5];
	entry[10] = funcAddress[6];
	entry[11] = funcAddress[7];
	asm("sti");
	cpu_enable_wp();

	LOG_DBG("done!\n");
	return;
}
}

extern "C"
{
int gdb_start_serverRing0(int port)
{
    LOG_DBG("gdb_start_server\n");

    // Prepare socket
	int r = ksocket_t(AF_INET, SOCK_STREAM, 0, RING0GDBMainThread);
	int client = 0;

	LOG_DBG("sys_socket: 0x%llx\n",r);

	if(r > 0)
	{
		int s = r;
        r = ps4gdb_sys_bindt(s,port,RING0GDBMainThread);

		LOG_DBG("sys_bind: 0x%llx\n",r);
		if(r == 0)
		{
			r = klisten_t(s, 10, RING0GDBMainThread);

			if(r == 0)
			{
                int r = kaccept_t(s, (struct sockaddr *) 0, 0, RING0GDBMainThread);
				LOG_DBG("Waiting for gdb connection on port %d\n", port);
                LOG_DBG("sys_accept: 0x%llx\n",r);

				if(r > 0)
				{
					client = r;
					LOG_DBG("Client socket fd: 0x%llx\n",client);
                    kshutdown_t(s,SHUT_RDWR, RING0GDBMainThread);
                    kclose_t(s,RING0GDBMainThread);
					return client;
				} else {
                    LOG_ERROR("Accept failed, killing proc to prevent kpanic\n");
                    return -1;
                }
			}
		} else {
            LOG_ERROR("Bind failed, killing proc to prevent kpanic\n");
        }
	}

	return r;
}
}


code:
.intel_syntax noprefix
.text
.global return_to_prog
.global catch_exception_03
.global catch_exception_01
.extern getRegistersAddress
.extern set_mem_err
.extern print_register_info
.extern gdb_close_client_socket

return_to_prog:
	// Restore RIP
	mov rdi, [rsp+0x40]
	mov [rsp+0x300], rdi

	// Restore flags
	mov rdi, [rsp+0x48]
	mov [rsp+0x310], rdi

	// Restore rsp
	mov rdi, [rsp+0x30]
	mov [rsp+0x318], rdi

	// Restore registers
	mov rdi, [rsp+0x00]
	mov rax, [rsp+0x08]
	mov rbx, [rsp+0x10]
	mov rcx, [rsp+0x18]
	mov rdx, [rsp+0x20]
	mov rsi, [rsp+0x28]
	mov rbp, [rsp+0x38]
	mov r8,  [rsp+0x50]
	mov r9,  [rsp+0x58]
	mov r10, [rsp+0x60]
	mov r11, [rsp+0x68]
	mov r12, [rsp+0x70]
	mov r13, [rsp+0x78]
	mov r14, [rsp+0x80]
	mov r15, [rsp+0x88]

	// Adjust stack
	add rsp,0x300
	// Return from interrupt
	iretq

catch_exception_01:
	// Make some space on stack
	sub rsp,0x300

	// Store registers
	mov [rsp+0x00],rdi
	mov [rsp+0x08],rax
	mov [rsp+0x10],rbx
	mov [rsp+0x18],rcx
	mov [rsp+0x20],rdx
	mov [rsp+0x28],rsi
	mov [rsp+0x38],rbp
	mov [rsp+0x50],r8
	mov [rsp+0x58],r9
	mov [rsp+0x60],r10
	mov [rsp+0x68],r11
	mov [rsp+0x70],r12
	mov [rsp+0x78],r13
	mov [rsp+0x80],r14
	mov [rsp+0x88],r15
	mov [rsp+0xA0],ds
	mov [rsp+0xA8],es
	mov [rsp+0xB0],fs
	mov [rsp+0xB8],gs

	// this int has no error code
	xor rsi,rsi
	mov [rsp+0xC0],rsi

    // Store old rsp value
	mov rsi,[rsp+0x318]
    mov [rsp+0x30],rsi

    // store return address
	mov rsi,[rsp+0x300]
	mov [rsp+0x40],rsi

	// store eflags
	mov rsi,[rsp+0x310]
   	mov [rsp+0x48], rsi

	// store cs
	mov rsi,[rsp+0x308]
	mov [rsp+0x90],rsi

	// store ss
	mov rsi,[rsp+0x320]
	mov [rsp+0x98],rsi

    // Call handler
	mov rdi,0x01
	xor rsi,rsi
	xor rdx,rdx
	mov rcx,rsp
	call handle_exceptionRing0
	jmp return_to_prog

catch_exception_03:
	// Make some space on stack
	sub rsp,0x300

	// Store registers
	mov [rsp+0x00],rdi
	mov [rsp+0x08],rax
	mov [rsp+0x10],rbx
	mov [rsp+0x18],rcx
	mov [rsp+0x20],rdx
	mov [rsp+0x28],rsi
	mov [rsp+0x38],rbp
	mov [rsp+0x50],r8
	mov [rsp+0x58],r9
	mov [rsp+0x60],r10
	mov [rsp+0x68],r11
	mov [rsp+0x70],r12
	mov [rsp+0x78],r13
	mov [rsp+0x80],r14
	mov [rsp+0x88],r15
	mov [rsp+0xA0],ds
	mov [rsp+0xA8],es
	mov [rsp+0xB0],fs
	mov [rsp+0xB8],gs

	// this int has no error code
	xor rsi,rsi
	mov [rsp+0xC0],rsi

    // Store old rsp value
	mov rsi,[rsp+0x318]
    mov [rsp+0x30],rsi

    // store return address
	mov rsi,[rsp+0x300]
	mov [rsp+0x40],rsi

	// store eflags
	mov rsi,[rsp+0x310]
   	mov [rsp+0x48], rsi

	// store cs
	mov rsi,[rsp+0x308]
	mov [rsp+0x90],rsi

	// store ss
	mov rsi,[rsp+0x320]
	mov [rsp+0x98],rsi

    // Call handler
	mov rdi,0x03
	xor rsi,rsi
	xor rdx,rdx
	mov rcx,rsp
	call handle_exceptionRing0
	jmp return_to_prog