Compare commits

...

13 Commits

Author SHA1 Message Date
Michael Scire
51d692dfba dmnt2: fix gdb register output 2021-11-02 16:56:13 -07:00
Michael Scire
545ade835d creport: fix errant ) 2021-11-02 10:10:47 -07:00
Michael Scire
be5cd35ef6 dmnt2: try to avoid writing out of bounds when generating packets 2021-11-02 10:09:15 -07:00
Michael Scire
d30af4763a dmnt2: fix module name detection, add auto-break on hb nro launch 2021-11-01 21:43:40 -07:00
jam1garner
7e110ee8f7 dmnt2: fix missing null-terminator for invalid command error 2021-11-01 21:15:58 -07:00
Michael Scire
ea61ac9ea6 dmnt2: detect thread name, add monitor get mapping(s), increase buffer sizes 2021-11-01 17:18:13 -07:00
Michael Scire
95ef9da873 dmnt2: remove memory-map output which does nothing for us 2021-11-01 12:43:18 -07:00
Michael Scire
d2b024f19f kern/dmnt2: allow retrieval of process info via extension
This also fixes ctrl-c break in gdbstub, and fixes crash on unknown monitor cmd.
2021-11-01 12:05:52 -07:00
Michael Scire
9011384dbe dmnt2: first pass at wait-for-application 2021-10-31 23:57:28 -07:00
Michael Scire
56669e34b7 dmnt2: add monitor get base, TODO responses for monitor wait * 2021-10-31 23:25:35 -07:00
Michael Scire
6df7a87727 dmnt2: add memory-map read, improve module shared-lib names 2021-10-31 18:32:23 -07:00
Michael Scire
90473a2307 Adding setting usage to dmnt2 means dmnt2 needs settings access 2021-10-31 15:54:32 -07:00
Michael Scire
29ffa4b7fd dmnt: enable experimental standalone usage of gdbstub, while starlink is in dev 2021-10-31 15:47:37 -07:00
34 changed files with 1249 additions and 368 deletions

View File

@@ -112,6 +112,7 @@ dist-no-debug: all
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042 mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420 mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240 mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623 mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
@@ -125,6 +126,7 @@ dist-no-debug: all
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp
cp stratosphere/dmnt.gen2/dmnt.gen2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp
cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs @build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
rm -r atmosphere-$(AMSVER)/stratosphere_romfs rm -r atmosphere-$(AMSVER)/stratosphere_romfs

View File

@@ -40,6 +40,12 @@
/* of the right side, and so this does not actually cost any space. */ /* of the right side, and so this does not actually cost any space. */
#define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST #define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST
/* NOTE: This enables usage of KDebug handles as parameter for svc::GetInfo */
/* calls which require a process parameter. This enables a debugger to obtain */
/* address space/layout information, for example. However, it changes abi, and so */
/* this define allows toggling the extension. */
#define MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS
/* NOTE: This uses currently-reserved bits inside the MapRange capability */ /* NOTE: This uses currently-reserved bits inside the MapRange capability */
/* in order to support large physical addresses (40-bit instead of 36). */ /* in order to support large physical addresses (40-bit instead of 36). */
/* This is toggleable in order to disable it if N ever uses those bits. */ /* This is toggleable in order to disable it if N ever uses those bits. */

View File

@@ -19,7 +19,7 @@ namespace ams::kern {
namespace { namespace {
constexpr std::tuple<KMemoryState, const char *> MemoryStateNames[] = { constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = {
{KMemoryState_Free , "----- Free -----"}, {KMemoryState_Free , "----- Free -----"},
{KMemoryState_Io , "Io "}, {KMemoryState_Io , "Io "},
{KMemoryState_Static , "Static "}, {KMemoryState_Static , "Static "},
@@ -41,6 +41,7 @@ namespace ams::kern {
{KMemoryState_Kernel , "Kernel "}, {KMemoryState_Kernel , "Kernel "},
{KMemoryState_GeneratedCode , "GeneratedCode "}, {KMemoryState_GeneratedCode , "GeneratedCode "},
{KMemoryState_CodeOut , "CodeOut "}, {KMemoryState_CodeOut , "CodeOut "},
{KMemoryState_Coverage , "Coverage "},
}; };
constexpr const char *GetMemoryStateName(KMemoryState state) { constexpr const char *GetMemoryStateName(KMemoryState state) {

View File

@@ -38,6 +38,80 @@ namespace ams::kern::svc {
return ResultSuccess(); return ResultSuccess();
} }
Result GetInfoImpl(u64 *out, ams::svc::InfoType info_type, KProcess *process) {
switch (info_type) {
case ams::svc::InfoType_CoreMask:
*out = process->GetCoreMask();
break;
case ams::svc::InfoType_PriorityMask:
*out = process->GetPriorityMask();
break;
case ams::svc::InfoType_AliasRegionAddress:
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
break;
case ams::svc::InfoType_AliasRegionSize:
*out = process->GetPageTable().GetAliasRegionSize();
break;
case ams::svc::InfoType_HeapRegionAddress:
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
break;
case ams::svc::InfoType_HeapRegionSize:
*out = process->GetPageTable().GetHeapRegionSize();
break;
case ams::svc::InfoType_TotalMemorySize:
*out = process->GetTotalUserPhysicalMemorySize();
break;
case ams::svc::InfoType_UsedMemorySize:
*out = process->GetUsedUserPhysicalMemorySize();
break;
case ams::svc::InfoType_AslrRegionAddress:
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
break;
case ams::svc::InfoType_AslrRegionSize:
*out = process->GetPageTable().GetAliasCodeRegionSize();
break;
case ams::svc::InfoType_StackRegionAddress:
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
break;
case ams::svc::InfoType_StackRegionSize:
*out = process->GetPageTable().GetStackRegionSize();
break;
case ams::svc::InfoType_SystemResourceSizeTotal:
*out = process->GetTotalSystemResourceSize();
break;
case ams::svc::InfoType_SystemResourceSizeUsed:
*out = process->GetUsedSystemResourceSize();
break;
case ams::svc::InfoType_ProgramId:
*out = process->GetProgramId();
break;
case ams::svc::InfoType_UserExceptionContextAddress:
*out = GetInteger(process->GetProcessLocalRegionAddress());
break;
case ams::svc::InfoType_TotalNonSystemMemorySize:
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
break;
case ams::svc::InfoType_UsedNonSystemMemorySize:
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
break;
case ams::svc::InfoType_IsApplication:
*out = process->IsApplication();
break;
case ams::svc::InfoType_FreeThreadCount:
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
*out = limit_value - current_value;
} else {
*out = 0;
}
break;
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
return ResultSuccess();
}
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) { Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
switch (info_type) { switch (info_type) {
case ams::svc::InfoType_CoreMask: case ams::svc::InfoType_CoreMask:
@@ -66,77 +140,34 @@ namespace ams::kern::svc {
/* Get the process from its handle. */ /* Get the process from its handle. */
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle); KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
#if defined(MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS)
/* If we the process is valid, use it. */
if (process.IsNotNull()) {
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
}
/* Otherwise, as a mesosphere extension check if we were passed a usable KDebug. */
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(handle);
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
/* Get the process from the debug object. */
/* TODO: ResultInvalidHandle()? */
R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated());
R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated());
/* Close the process when we're done. */
ON_SCOPE_EXIT { debug->CloseProcess(); };
/* Return the info. */
return GetInfoImpl(out, info_type, debug->GetProcessUnsafe());
#else
/* Verify that the process is valid. */
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
switch (info_type) { /* Return the relevant info. */
case ams::svc::InfoType_CoreMask: return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
*out = process->GetCoreMask(); #endif
break;
case ams::svc::InfoType_PriorityMask:
*out = process->GetPriorityMask();
break;
case ams::svc::InfoType_AliasRegionAddress:
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
break;
case ams::svc::InfoType_AliasRegionSize:
*out = process->GetPageTable().GetAliasRegionSize();
break;
case ams::svc::InfoType_HeapRegionAddress:
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
break;
case ams::svc::InfoType_HeapRegionSize:
*out = process->GetPageTable().GetHeapRegionSize();
break;
case ams::svc::InfoType_TotalMemorySize:
*out = process->GetTotalUserPhysicalMemorySize();
break;
case ams::svc::InfoType_UsedMemorySize:
*out = process->GetUsedUserPhysicalMemorySize();
break;
case ams::svc::InfoType_AslrRegionAddress:
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
break;
case ams::svc::InfoType_AslrRegionSize:
*out = process->GetPageTable().GetAliasCodeRegionSize();
break;
case ams::svc::InfoType_StackRegionAddress:
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
break;
case ams::svc::InfoType_StackRegionSize:
*out = process->GetPageTable().GetStackRegionSize();
break;
case ams::svc::InfoType_SystemResourceSizeTotal:
*out = process->GetTotalSystemResourceSize();
break;
case ams::svc::InfoType_SystemResourceSizeUsed:
*out = process->GetUsedSystemResourceSize();
break;
case ams::svc::InfoType_ProgramId:
*out = process->GetProgramId();
break;
case ams::svc::InfoType_UserExceptionContextAddress:
*out = GetInteger(process->GetProcessLocalRegionAddress());
break;
case ams::svc::InfoType_TotalNonSystemMemorySize:
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
break;
case ams::svc::InfoType_UsedNonSystemMemorySize:
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
break;
case ams::svc::InfoType_IsApplication:
*out = process->IsApplication();
break;
case ams::svc::InfoType_FreeThreadCount:
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
*out = limit_value - current_value;
} else {
*out = 0;
}
break;
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
} }
break; break;
case ams::svc::InfoType_DebuggerAttached: case ams::svc::InfoType_DebuggerAttached:

View File

@@ -118,12 +118,12 @@ namespace ams::fssystem {
/* Copy API. */ /* Copy API. */
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size); Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) { ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size); return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
} }
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size); Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) { ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size); return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
} }
@@ -148,11 +148,11 @@ namespace ams::fssystem {
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
template<typename F> template<s64 RetryMilliSeconds = 100>
NX_INLINE Result RetryFinitelyForTargetLocked(F f) { ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) {
/* Retry up to 10 times, 100ms between retries. */ /* Retry up to 10 times, 100ms between retries. */
constexpr s32 MaxRetryCount = 10; constexpr s32 MaxRetryCount = 10;
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(100); constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds);
s32 remaining_retries = MaxRetryCount; s32 remaining_retries = MaxRetryCount;
while (true) { while (true) {

View File

@@ -43,6 +43,7 @@ namespace ams::socket {
s32 Shutdown(s32 desc, ShutdownMethod how); s32 Shutdown(s32 desc, ShutdownMethod how);
s32 Socket(Family domain, Type type, Protocol protocol);
s32 SocketExempt(Family domain, Type type, Protocol protocol); s32 SocketExempt(Family domain, Type type, Protocol protocol);
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len); s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);

View File

@@ -57,4 +57,42 @@ namespace ams::socket {
} }
}; };
class SystemConfigLightDefault : public Config {
public:
static constexpr size_t DefaultTcpInitialSendBufferSize = 16_KB;
static constexpr size_t DefaultTcpInitialReceiveBufferSize = 16_KB;
static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 0_KB;
static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 0_KB;
static constexpr size_t DefaultUdpSendBufferSize = 9_KB;
static constexpr size_t DefaultUdpReceiveBufferSize = 42240;
static constexpr auto DefaultSocketBufferEfficiency = 2;
static constexpr auto DefaultConcurrency = 2;
static constexpr size_t DefaultAllocatorPoolSize = 64_KB;
static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] {
constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax));
constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax));
return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
}();
static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] {
constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize);
constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize);
return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
}();
public:
constexpr SystemConfigLightDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency)
: Config(mp, mp_sz, ap,
DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize,
DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax,
DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize,
DefaultSocketBufferEfficiency, c)
{
/* Mark as system. */
m_system = true;
}
};
} }

View File

@@ -188,6 +188,12 @@ namespace ams::boot2 {
return enable_htc != 0; return enable_htc != 0;
} }
bool IsStandaloneGdbstubEnabled() {
u8 enable_gdbstub = 0;
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
return enable_gdbstub != 0;
}
bool IsAtmosphereLogManagerEnabled() { bool IsAtmosphereLogManagerEnabled() {
/* If htc is enabled, ams log manager is enabled. */ /* If htc is enabled, ams log manager is enabled. */
if (IsHtcEnabled()) { if (IsHtcEnabled()) {
@@ -403,6 +409,9 @@ namespace ams::boot2 {
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0);
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0);
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
} else if (IsStandaloneGdbstubEnabled()) {
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
} else { } else {
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0);
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);

View File

@@ -52,6 +52,26 @@ namespace ams::os::impl {
/* Get the thread impl object from libnx. */ /* Get the thread impl object from libnx. */
ThreadImpl *thread_impl = ::threadGetSelf(); ThreadImpl *thread_impl = ::threadGetSelf();
/* Hack around libnx's main thread, to ensure stratosphere thread type consistency. */
{
auto *tlr = reinterpret_cast<uintptr_t *>(svc::GetThreadLocalRegion());
for (size_t i = sizeof(svc::ThreadLocalRegion) / sizeof(uintptr_t); i > 0; --i) {
if (auto *candidate = reinterpret_cast<ThreadImpl *>(tlr[i - 1]); candidate == thread_impl) {
ThreadImpl *embedded_thread = std::addressof(main_thread->thread_impl_storage);
*embedded_thread = *thread_impl;
if (embedded_thread->next) {
embedded_thread->next->prev_next = std::addressof(embedded_thread->next);
}
thread_impl = embedded_thread;
tlr[i-1] = reinterpret_cast<uintptr_t>(thread_impl);
break;
}
}
}
/* Get the thread priority. */ /* Get the thread priority. */
s32 horizon_priority; s32 horizon_priority;
R_ABORT_UNLESS(svc::GetThreadPriority(std::addressof(horizon_priority), thread_impl->handle)); R_ABORT_UNLESS(svc::GetThreadPriority(std::addressof(horizon_priority), thread_impl->handle));

View File

@@ -54,7 +54,7 @@ namespace ams::osdbg::impl {
static_assert(AMS_OFFSETOF(ThreadLocalRegionIlp32, tls) == 0x1C0); static_assert(AMS_OFFSETOF(ThreadLocalRegionIlp32, tls) == 0x1C0);
struct LibnxThreadVars { struct LibnxThreadVars {
static constexpr u32 Magic = util::FourCC<'!','T','V','$'>::Code; static constexpr u32 Magic = util::ReverseFourCC<'!','T','V','$'>::Code;
u32 magic; u32 magic;
::Handle handle; ::Handle handle;
@@ -69,11 +69,11 @@ namespace ams::osdbg::impl {
volatile u16 disable_counter; volatile u16 disable_counter;
volatile u16 interrupt_flag; volatile u16 interrupt_flag;
u32 reserved0; u32 reserved0;
u64 tls[(0x1E0 - 0x108) / sizeof(u64)]; u64 tls[(0x200 - sizeof(LibnxThreadVars) - 0x108) / sizeof(u64)];
LibnxThreadVars thread_vars; LibnxThreadVars thread_vars;
}; };
static_assert(sizeof(ThreadLocalRegionLibnx) == sizeof(svc::ThreadLocalRegion)); static_assert(sizeof(ThreadLocalRegionLibnx) == sizeof(svc::ThreadLocalRegion));
static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x1E0); static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x200 - sizeof(LibnxThreadVars));
struct LibnxThreadEntryArgs { struct LibnxThreadEntryArgs {
u64 t; u64 t;

View File

@@ -50,9 +50,9 @@ namespace ams::osdbg {
} else { } else {
/* Special-case libnx threads. */ /* Special-case libnx threads. */
if (thread_info->_thread_type_type == ThreadTypeType_Libnx) { if (thread_info->_thread_type_type == ThreadTypeType_Libnx) {
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type)); util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
} else { } else {
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type)); util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
} }
return ResultSuccess(); return ResultSuccess();

View File

@@ -41,6 +41,7 @@ namespace ams::socket::impl {
s32 Shutdown(s32 desc, ShutdownMethod how); s32 Shutdown(s32 desc, ShutdownMethod how);
s32 Socket(Family domain, Type type, Protocol protocol);
s32 SocketExempt(Family domain, Type type, Protocol protocol); s32 SocketExempt(Family domain, Type type, Protocol protocol);
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len); s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);

View File

@@ -206,6 +206,8 @@ namespace ams::socket::impl {
/* TODO: socket::resolver::EnableResolverCalls()? Not necessary in our case (htc), but consider calling it. */ /* TODO: socket::resolver::EnableResolverCalls()? Not necessary in our case (htc), but consider calling it. */
g_initialized = true;
return ResultSuccess(); return ResultSuccess();
} }
@@ -422,6 +424,22 @@ namespace ams::socket::impl {
return result; return result;
} }
s32 Socket(Family domain, Type type, Protocol protocol) {
/* Check pre-conditions. */
AMS_ABORT_UNLESS(IsInitialized());
/* Perform the call. */
Errno error = Errno::ESuccess;
int result = ::bsdSocket(static_cast<int>(domain), static_cast<int>(type), static_cast<int>(protocol));
TranslateResultToBsdError(error, result);
if (result < 0) {
socket::impl::SetLastError(error);
}
return result;
}
s32 SocketExempt(Family domain, Type type, Protocol protocol) { s32 SocketExempt(Family domain, Type type, Protocol protocol) {
/* Check pre-conditions. */ /* Check pre-conditions. */
AMS_ABORT_UNLESS(IsInitialized()); AMS_ABORT_UNLESS(IsInitialized());

View File

@@ -74,6 +74,10 @@ namespace ams::socket {
return impl::Shutdown(desc, how); return impl::Shutdown(desc, how);
} }
s32 Socket(Family domain, Type type, Protocol protocol) {
return impl::Socket(domain, type, protocol);
}
s32 SocketExempt(Family domain, Type type, Protocol protocol) { s32 SocketExempt(Family domain, Type type, Protocol protocol) {
return impl::SocketExempt(domain, type, protocol); return impl::SocketExempt(domain, type, protocol);
} }

View File

@@ -378,6 +378,12 @@ namespace ams::settings::fwdbg {
/* 0 = Disabled, 1 = Enabled */ /* 0 = Disabled, 1 = Enabled */
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0")); R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_htc", "u8!0x0"));
/* Controls whether atmosphere's dmnt.gen2 gdbstub should run as a standalone via sockets. */
/* Note that this setting is ignored (and treated as 0) when htc is enabled. */
/* Note that this setting may disappear in the future. */
/* 0 = Disabled, 1 = Enabled */
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_standalone_gdbstub", "u8!0x0"));
/* Controls whether atmosphere's log manager is enabled. */ /* Controls whether atmosphere's log manager is enabled. */
/* Note that this setting is ignored (and treated as 1) when htc is enabled. */ /* Note that this setting is ignored (and treated as 1) when htc is enabled. */
/* 0 = Disabled, 1 = Enabled */ /* 0 = Disabled, 1 = Enabled */

View File

@@ -27,7 +27,7 @@ namespace ams::creport {
struct ModulePath { struct ModulePath {
u32 zero; u32 zero;
u32 path_length; s32 path_length;
char path[ModulePathLengthMax]; char path[ModulePathLengthMax];
}; };
static_assert(sizeof(ModulePath) == 0x208, "ModulePath definition!"); static_assert(sizeof(ModulePath) == 0x208, "ModulePath definition!");
@@ -210,7 +210,7 @@ namespace ams::creport {
} }
/* Also validate that we're looking at a valid name. */ /* Also validate that we're looking at a valid name. */
if (rodata_start.module_path.zero != 0 || rodata_start.module_path.path_length != strnlen(rodata_start.module_path.path, sizeof(rodata_start.module_path.path))) { if (rodata_start.module_path.zero != 0 || rodata_start.module_path.path_length <= 0) {
return; return;
} }
} }
@@ -219,7 +219,7 @@ namespace ams::creport {
/* Start after last slash in path. */ /* Start after last slash in path. */
const char *path = rodata_start.module_path.path; const char *path = rodata_start.module_path.path;
int ofs; int ofs;
for (ofs = rodata_start.module_path.path_length; ofs >= 0; ofs--) { for (ofs = std::min<size_t>(rodata_start.module_path.path_length, sizeof(rodata_start.module_path.path)); ofs >= 0; ofs--) {
if (path[ofs] == '/' || path[ofs] == '\\') { if (path[ofs] == '/' || path[ofs] == '\\') {
break; break;
} }
@@ -227,8 +227,8 @@ namespace ams::creport {
ofs++; ofs++;
/* Copy name to output. */ /* Copy name to output. */
const size_t name_size = std::min(ModuleNameLengthMax, sizeof(rodata_start.module_path.path) - ofs); const size_t name_size = std::min(ModuleNameLengthMax, std::min<size_t>(rodata_start.module_path.path_length, sizeof(rodata_start.module_path.path)) - ofs);
std::strncpy(out_name, path + ofs, name_size); std::memcpy(out_name, path + ofs, name_size);
out_name[ModuleNameLengthMax - 1] = '\x00'; out_name[ModuleNameLengthMax - 1] = '\x00';
} }

View File

@@ -15,7 +15,7 @@
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },
"service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs"], "service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs", "bsd:s", "set:sys"],
"service_host": [], "service_host": [],
"kernel_capabilities": [{ "kernel_capabilities": [{
"type": "kernel_flags", "type": "kernel_flags",

View File

@@ -16,7 +16,8 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_debug_log.hpp" #include "dmnt2_debug_log.hpp"
#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG // TODO: This should be converted to use log manager. */
//#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
#if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG) #if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG)
@@ -164,15 +165,78 @@ namespace ams::dmnt {
namespace ams::dmnt { namespace ams::dmnt {
//#define AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG
#if defined(AMS_DMNT2_ENABLE_SD_CARD_DEBUG_LOG)
namespace {
alignas(0x40) constinit u8 g_buffer[os::MemoryPageSize * 4];
constinit lmem::HeapHandle g_debug_log_heap;
constinit fs::FileHandle g_debug_log_file;
constinit os::SdkMutex g_fs_mutex;
constinit s64 g_fs_offset = 0;
void *Allocate(size_t size) {
return lmem::AllocateFromExpHeap(g_debug_log_heap, size);
}
void Deallocate(void *p, size_t size) {
AMS_UNUSED(size);
return lmem::FreeToExpHeap(g_debug_log_heap, p);
}
}
void InitializeDebugLog() { void InitializeDebugLog() {
/* Do nothing. */ g_debug_log_heap = lmem::CreateExpHeap(g_buffer, sizeof(g_buffer), lmem::CreateOption_ThreadSafe);
fs::SetAllocator(Allocate, Deallocate);
fs::InitializeForSystem();
fs::SetEnabledAutoAbort(false);
R_ABORT_UNLESS(fs::MountSdCard("sdmc"));
fs::DeleteFile("sdmc:/dmnt2.log");
R_ABORT_UNLESS(fs::CreateFile("sdmc:/dmnt2.log", 0));
R_ABORT_UNLESS(fs::OpenFile(std::addressof(g_debug_log_file), "sdmc:/dmnt2.log", fs::OpenMode_Write | fs::OpenMode_AllowAppend));
} }
void DebugLog(const char *prefix, const char *fmt, ...) { void DebugLog(const char *prefix, const char *fmt, ...) {
/* Do nothing. */ /* Do nothing. */
char buffer[0x200];
{
const auto prefix_len = std::strlen(prefix);
std::memcpy(buffer, prefix, prefix_len);
std::va_list vl;
va_start(vl, fmt);
util::VSNPrintf(buffer + prefix_len, sizeof(buffer) - prefix_len, fmt, vl);
va_end(vl);
}
const auto len = std::strlen(buffer);
std::scoped_lock lk(g_fs_mutex);
R_ABORT_UNLESS(fs::WriteFile(g_debug_log_file, g_fs_offset, buffer, len, fs::WriteOption::Flush));
g_fs_offset += len;
} }
#else
void InitializeDebugLog() {
/* ... */
}
void DebugLog(const char *prefix, const char *fmt, ...) {
AMS_UNUSED(prefix, fmt);
}
#endif
} }

View File

@@ -27,10 +27,15 @@ namespace ams::dmnt {
} }
Result DebugProcess::Attach(os::ProcessId process_id) { Result DebugProcess::Attach(os::ProcessId process_id, bool start_process) {
/* Attach to the process. */ /* Attach to the process. */
R_TRY(svc::DebugActiveProcess(std::addressof(m_debug_handle), process_id.value)); R_TRY(svc::DebugActiveProcess(std::addressof(m_debug_handle), process_id.value));
/* If necessary, start the process. */
if (start_process) {
R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id));
}
/* Collect initial information. */ /* Collect initial information. */
R_TRY(this->Start()); R_TRY(this->Start());
@@ -42,6 +47,10 @@ namespace ams::dmnt {
svc::GetProcessId(std::addressof(pid_value), m_debug_handle); svc::GetProcessId(std::addressof(pid_value), m_debug_handle);
m_process_id = { pid_value }; m_process_id = { pid_value };
/* Get process info. */
this->CollectProcessInfo();
return ResultSuccess(); return ResultSuccess();
} }
@@ -187,13 +196,25 @@ namespace ams::dmnt {
char path[ModuleDefinition::PathLengthMax]; char path[ModuleDefinition::PathLengthMax];
} module_path; } module_path;
if (R_SUCCEEDED(this->ReadMemory(std::addressof(module_path), memory_info.base_address + memory_info.size, sizeof(module_path)))) { if (R_SUCCEEDED(this->ReadMemory(std::addressof(module_path), memory_info.base_address + memory_info.size, sizeof(module_path)))) {
if (module_path.zero == 0 && module_path.path_length == util::Strnlen(module_path.path, sizeof(module_path.path))) { if (module_path.zero == 0 && module_path.path_length > 0) {
std::memcpy(module_name, module_path.path, ModuleDefinition::PathLengthMax); std::memcpy(module_name, module_path.path, std::min<size_t>(ModuleDefinition::PathLengthMax, module_path.path_length));
} }
} else {
module_path.path_length = 0;
} }
/* Truncate module name. */ /* Truncate module name. */
module_name[ModuleDefinition::PathLengthMax - 1] = 0; module_name[ModuleDefinition::PathLengthMax - 1] = 0;
/* Set default module name start. */
module.SetNameStart(0);
/* Ignore leading directories. */
for (size_t i = 0; i < std::min<size_t>(ModuleDefinition::PathLengthMax, module_path.path_length) && module_name[i] != 0; ++i) {
if (module_name[i] == '/' || module_name[i] == '\\') {
module.SetNameStart(i + 1);
}
}
} }
} }
@@ -212,6 +233,53 @@ namespace ams::dmnt {
return ResultSuccess(); return ResultSuccess();
} }
void DebugProcess::CollectProcessInfo() {
/* Define helper for getting process info. */
auto CollectProcessInfoImpl = [&](os::NativeHandle handle) -> Result {
/* Collect all values. */
R_TRY(svc::GetInfo(std::addressof(m_process_alias_address), svc::InfoType_AliasRegionAddress, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_alias_size), svc::InfoType_AliasRegionSize, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_heap_address), svc::InfoType_HeapRegionAddress, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_heap_size), svc::InfoType_HeapRegionSize, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_aslr_address), svc::InfoType_AslrRegionAddress, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_aslr_size), svc::InfoType_AslrRegionSize, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_stack_address), svc::InfoType_StackRegionAddress, handle, 0));
R_TRY(svc::GetInfo(std::addressof(m_process_stack_size), svc::InfoType_StackRegionSize, handle, 0));
if (m_program_location.program_id == ncm::InvalidProgramId) {
R_TRY(svc::GetInfo(std::addressof(m_program_location.program_id.value), svc::InfoType_ProgramId, handle, 0));
}
u64 value;
R_TRY(svc::GetInfo(std::addressof(value), svc::InfoType_IsApplication, handle, 0));
m_is_application = value != 0;
return ResultSuccess();
};
/* Get process info/status. */
os::NativeHandle process_handle;
if (R_FAILED(pm::dmnt::AtmosphereGetProcessInfo(std::addressof(process_handle), std::addressof(m_program_location), std::addressof(m_process_override_status), m_process_id))) {
process_handle = os::InvalidNativeHandle;
m_program_location = { ncm::InvalidProgramId, };
m_process_override_status = {};
}
ON_SCOPE_EXIT { os::CloseNativeHandle(process_handle); };
/* Try collecting from our debug handle, then the process handle. */
if (R_FAILED(CollectProcessInfoImpl(m_debug_handle)) && R_FAILED(CollectProcessInfoImpl(process_handle))) {
m_process_alias_address = 0;
m_process_alias_size = 0;
m_process_heap_address = 0;
m_process_heap_size = 0;
m_process_aslr_address = 0;
m_process_aslr_size = 0;
m_process_stack_address = 0;
m_process_stack_size = 0;
m_is_application = false;
}
}
Result DebugProcess::GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags) { Result DebugProcess::GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags) {
return svc::GetDebugThreadContext(out, m_debug_handle, thread_id, flags); return svc::GetDebugThreadContext(out, m_debug_handle, thread_id, flags);
} }
@@ -228,6 +296,11 @@ namespace ams::dmnt {
return svc::WriteDebugProcessMemory(m_debug_handle, reinterpret_cast<uintptr_t>(src), address, size); return svc::WriteDebugProcessMemory(m_debug_handle, reinterpret_cast<uintptr_t>(src), address, size);
} }
Result DebugProcess::QueryMemory(svc::MemoryInfo *out, uintptr_t address) {
svc::PageInfo dummy;
return svc::QueryDebugProcessMemory(out, std::addressof(dummy), m_debug_handle, address);
}
Result DebugProcess::Continue() { Result DebugProcess::Continue() {
AMS_DMNT2_GDB_LOG_DEBUG("DebugProcess::Continue() all\n"); AMS_DMNT2_GDB_LOG_DEBUG("DebugProcess::Continue() all\n");
@@ -522,5 +595,25 @@ namespace ams::dmnt {
return ResultSuccess(); return ResultSuccess();
} }
void DebugProcess::GetThreadName(char *dst, u64 thread_id) const {
for (size_t i = 0; i < ThreadCountMax; ++i) {
if (m_thread_valid[i] && m_thread_ids[i] == thread_id) {
if (R_FAILED(osdbg::GetThreadName(dst, std::addressof(m_thread_infos[i])))) {
if (m_thread_infos[i]._thread_type != 0) {
if (m_thread_infos[i]._thread_type_type == osdbg::ThreadTypeType_Libnx) {
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast<uintptr_t>(m_thread_infos[i]._thread_type));
} else {
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast<uintptr_t>(m_thread_infos[i]._thread_type));
}
} else {
break;
}
}
return;
}
}
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_ID=%lu", thread_id);
}
} }

View File

@@ -50,6 +50,7 @@ namespace ams::dmnt {
u64 m_last_thread_id{}; u64 m_last_thread_id{};
u64 m_thread_id_override{}; u64 m_thread_id_override{};
u64 m_continue_thread_id{}; u64 m_continue_thread_id{};
u64 m_preferred_debug_break_thread_id{};
GdbSignal m_last_signal{}; GdbSignal m_last_signal{};
bool m_stepping{false}; bool m_stepping{false};
bool m_use_hardware_single_step{false}; bool m_use_hardware_single_step{false};
@@ -64,6 +65,17 @@ namespace ams::dmnt {
ModuleDefinition m_module_definitions[ModuleCountMax]{}; ModuleDefinition m_module_definitions[ModuleCountMax]{};
size_t m_module_count{}; size_t m_module_count{};
size_t m_main_module{}; size_t m_main_module{};
u64 m_process_alias_address{};
u64 m_process_alias_size{};
u64 m_process_heap_address{};
u64 m_process_heap_size{};
u64 m_process_aslr_address{};
u64 m_process_aslr_size{};
u64 m_process_stack_address{};
u64 m_process_stack_size{};
ncm::ProgramLocation m_program_location{};
cfg::OverrideStatus m_process_override_status{};
bool m_is_application{false};
public: public:
DebugProcess() : m_software_breakpoints(this), m_hardware_breakpoints(this), m_hardware_watchpoints(this), m_step_breakpoints(m_software_breakpoints) { DebugProcess() : m_software_breakpoints(this), m_hardware_breakpoints(this), m_hardware_watchpoints(this), m_step_breakpoints(m_software_breakpoints) {
if (svc::IsKernelMesosphere()) { if (svc::IsKernelMesosphere()) {
@@ -80,7 +92,8 @@ namespace ams::dmnt {
size_t GetModuleCount() const { return m_module_count; } size_t GetModuleCount() const { return m_module_count; }
size_t GetMainModuleIndex() const { return m_main_module; } size_t GetMainModuleIndex() const { return m_main_module; }
const char *GetModuleName(size_t ix) const { return m_module_definitions[ix].GetName(); } const char *GetModuleName(size_t ix) const { return m_module_definitions[ix].GetName(); }
uintptr_t GetBaseAddress(size_t ix) const { return m_module_definitions[ix].GetAddress(); } uintptr_t GetModuleBaseAddress(size_t ix) const { return m_module_definitions[ix].GetAddress(); }
uintptr_t GetModuleSize(size_t ix) const { return m_module_definitions[ix].GetSize(); }
ProcessStatus GetStatus() const { return m_status; } ProcessStatus GetStatus() const { return m_status; }
os::ProcessId GetProcessId() const { return m_process_id; } os::ProcessId GetProcessId() const { return m_process_id; }
@@ -95,20 +108,37 @@ namespace ams::dmnt {
u64 GetLastThreadId(); u64 GetLastThreadId();
u64 GetThreadIdOverride() { this->GetLastThreadId(); return m_thread_id_override; } u64 GetThreadIdOverride() { this->GetLastThreadId(); return m_thread_id_override; }
u64 GetPreferredDebuggerBreakThreadId() { return m_preferred_debug_break_thread_id; }
void SetLastThreadId(u64 tid) { void SetLastThreadId(u64 tid) {
m_last_thread_id = tid; m_last_thread_id = tid;
m_thread_id_override = tid; m_thread_id_override = tid;
} }
void SetThreadIdOverride(u64 tid) { void SetThreadIdOverride(u64 tid) {
m_thread_id_override = tid; m_thread_id_override = tid;
m_preferred_debug_break_thread_id = tid;
} }
void SetDebugBreaked() { void SetDebugBreaked() {
m_status = ProcessStatus_DebugBreak; m_status = ProcessStatus_DebugBreak;
} }
u64 GetAliasRegionAddress() const { return m_process_alias_address; }
u64 GetAliasRegionSize() const { return m_process_alias_size; }
u64 GetHeapRegionAddress() const { return m_process_heap_address; }
u64 GetHeapRegionSize() const { return m_process_heap_size; }
u64 GetAslrRegionAddress() const { return m_process_aslr_address; }
u64 GetAslrRegionSize() const { return m_process_aslr_size; }
u64 GetStackRegionAddress() const { return m_process_stack_address; }
u64 GetStackRegionSize() const { return m_process_stack_size; }
const ncm::ProgramLocation &GetProgramLocation() const { return m_program_location; }
const cfg::OverrideStatus &GetOverrideStatus() const { return m_process_override_status; }
bool IsApplication() const { return m_is_application; }
public: public:
Result Attach(os::ProcessId process_id); Result Attach(os::ProcessId process_id, bool start_process = false);
void Detach(); void Detach();
Result GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags); Result GetThreadContext(svc::ThreadContext *out, u64 thread_id, u32 flags);
@@ -117,6 +147,8 @@ namespace ams::dmnt {
Result ReadMemory(void *dst, uintptr_t address, size_t size); Result ReadMemory(void *dst, uintptr_t address, size_t size);
Result WriteMemory(const void *src, uintptr_t address, size_t size); Result WriteMemory(const void *src, uintptr_t address, size_t size);
Result QueryMemory(svc::MemoryInfo *out, uintptr_t address);
Result Continue(); Result Continue();
Result Continue(u64 thread_id); Result Continue(u64 thread_id);
Result Step(); Result Step();
@@ -146,9 +178,13 @@ namespace ams::dmnt {
void GetBranchTarget(svc::ThreadContext &ctx, u64 thread_id, u64 &current_pc, u64 &target); void GetBranchTarget(svc::ThreadContext &ctx, u64 thread_id, u64 &current_pc, u64 &target);
Result CollectModules(); Result CollectModules();
void GetThreadName(char *dst, u64 thread_id) const;
private: private:
Result Start(); Result Start();
void CollectProcessInfo();
s32 ThreadCreate(u64 thread_id); s32 ThreadCreate(u64 thread_id);
void ThreadExit(u64 thread_id); void ThreadExit(u64 thread_id);
}; };

View File

@@ -41,7 +41,7 @@ namespace ams::dmnt {
} }
void GdbPacketIo::SendPacket(bool *out_break, const char *src, HtcsSession *session) { void GdbPacketIo::SendPacket(bool *out_break, const char *src, TransportSession *session) {
/* Default to not breaked. */ /* Default to not breaked. */
*out_break = false; *out_break = false;
@@ -99,7 +99,7 @@ namespace ams::dmnt {
} }
} }
char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session) { char *GdbPacketIo::ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session) {
/* Default to not breaked. */ /* Default to not breaked. */
*out_break = false; *out_break = false;

View File

@@ -15,11 +15,11 @@
*/ */
#pragma once #pragma once
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_htcs_session.hpp" #include "dmnt2_transport_session.hpp"
namespace ams::dmnt { namespace ams::dmnt {
static constexpr size_t GdbPacketBufferSize = 16_KB; static constexpr size_t GdbPacketBufferSize = 32_KB;
class GdbPacketIo { class GdbPacketIo {
private: private:
@@ -30,8 +30,8 @@ namespace ams::dmnt {
void SetNoAck() { m_no_ack = true; } void SetNoAck() { m_no_ack = true; }
void SendPacket(bool *out_break, const char *src, HtcsSession *session); void SendPacket(bool *out_break, const char *src, TransportSession *session);
char *ReceivePacket(bool *out_break, char *dst, size_t size, HtcsSession *session); char *ReceivePacket(bool *out_break, char *dst, size_t size, TransportSession *session);
}; };
} }

View File

@@ -15,6 +15,7 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_debug_log.hpp" #include "dmnt2_debug_log.hpp"
#include "dmnt2_transport_layer.hpp"
#include "dmnt2_gdb_server.hpp" #include "dmnt2_gdb_server.hpp"
#include "dmnt2_gdb_server_impl.hpp" #include "dmnt2_gdb_server_impl.hpp"
@@ -36,34 +37,28 @@ namespace ams::dmnt {
while (true) { while (true) {
/* Get a socket. */ /* Get a socket. */
int fd; int fd;
while ((fd = htcs::Socket()) == -1) { while ((fd = transport::Socket()) == -1) {
os::SleepThread(TimeSpan::FromSeconds(1)); os::SleepThread(TimeSpan::FromSeconds(1));
} }
/* Ensure we cleanup the socket when we're done with it. */ /* Ensure we cleanup the socket when we're done with it. */
ON_SCOPE_EXIT { ON_SCOPE_EXIT {
htcs::Close(fd); transport::Close(fd);
os::SleepThread(TimeSpan::FromSeconds(1)); os::SleepThread(TimeSpan::FromSeconds(1));
}; };
/* Create a sock addr for our server. */
htcs::SockAddrHtcs addr;
addr.family = htcs::HTCS_AF_HTCS;
addr.peer_name = htcs::GetPeerNameAny();
std::strcpy(addr.port_name.name, "iywys@$gdb");
/* Bind. */ /* Bind. */
if (htcs::Bind(fd, std::addressof(addr)) == -1) { if (transport::Bind(fd, transport::PortName_GdbServer) == -1) {
continue; continue;
} }
/* Listen on our port. */ /* Listen on our port. */
while (htcs::Listen(fd, 0) == 0) { while (transport::Listen(fd, 0) == 0) {
/* Continue accepting clients, so long as we can. */ /* Continue accepting clients, so long as we can. */
int client_fd; int client_fd;
while (true) { while (true) {
/* Try to accept a client. */ /* Try to accept a client. */
if (client_fd = htcs::Accept(fd, std::addressof(addr)); client_fd < 0) { if (client_fd = transport::Accept(fd); client_fd < 0) {
break; break;
} }
@@ -77,7 +72,7 @@ namespace ams::dmnt {
} }
/* Close the client socket. */ /* Close the client socket. */
htcs::Close(client_fd); transport::Close(client_fd);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -31,10 +31,11 @@ namespace ams::dmnt {
}; };
private: private:
int m_socket; int m_socket;
HtcsSession m_session; TransportSession m_session;
GdbPacketIo m_packet_io; GdbPacketIo m_packet_io;
char *m_receive_packet{nullptr}; char *m_receive_packet{nullptr};
char *m_reply_packet{nullptr}; char *m_reply_cur{nullptr};
char *m_reply_end{nullptr};
char m_buffer[GdbPacketBufferSize / 2]; char m_buffer[GdbPacketBufferSize / 2];
bool m_killed{false}; bool m_killed{false};
os::ThreadType m_events_thread; os::ThreadType m_events_thread;
@@ -42,6 +43,7 @@ namespace ams::dmnt {
DebugProcess m_debug_process; DebugProcess m_debug_process;
os::ProcessId m_process_id{os::InvalidProcessId}; os::ProcessId m_process_id{os::InvalidProcessId};
os::Event m_event; os::Event m_event;
os::ProcessId m_wait_process_id{os::InvalidProcessId};
public: public:
GdbServerImpl(int socket, void *thread_stack, size_t stack_size); GdbServerImpl(int socket, void *thread_stack, size_t stack_size);
~GdbServerImpl(); ~GdbServerImpl();
@@ -60,7 +62,7 @@ namespace ams::dmnt {
static void DebugEventsThreadEntry(void *arg) { static_cast<GdbServerImpl *>(arg)->DebugEventsThread(); } static void DebugEventsThreadEntry(void *arg) { static_cast<GdbServerImpl *>(arg)->DebugEventsThread(); }
void DebugEventsThread(); void DebugEventsThread();
void ProcessDebugEvents(); void ProcessDebugEvents();
void SetStopReplyPacket(GdbSignal signal); void AppendStopReplyPacket(GdbSignal signal);
private: private:
void D(); void D();
@@ -98,6 +100,7 @@ namespace ams::dmnt {
void qAttached(); void qAttached();
void qC(); void qC();
void qRcmd();
void qSupported(); void qSupported();
void qXfer(); void qXfer();
void qXferFeaturesRead(); void qXferFeaturesRead();

View File

@@ -16,15 +16,22 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_debug_log.hpp" #include "dmnt2_debug_log.hpp"
#include "dmnt2_gdb_server.hpp" #include "dmnt2_gdb_server.hpp"
#include "dmnt2_transport_layer.hpp"
namespace ams { namespace ams {
namespace dmnt { namespace {
namespace { bool IsHtcEnabled() {
u8 enable_htc = 0;
alignas(0x40) constinit u8 g_htcs_buffer[4_KB]; settings::fwdbg::GetSettingsItemValue(std::addressof(enable_htc), sizeof(enable_htc), "atmosphere", "enable_htc");
return enable_htc != 0;
}
bool IsStandaloneGdbstubEnabled() {
u8 enable_gdbstub = 0;
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
return enable_gdbstub != 0;
} }
} }
@@ -35,6 +42,9 @@ namespace ams {
/* Initialize our connection to sm. */ /* Initialize our connection to sm. */
R_ABORT_UNLESS(sm::Initialize()); R_ABORT_UNLESS(sm::Initialize());
/* Initialize other services we need. */
R_ABORT_UNLESS(pmdmntInitialize());
/* Verify that we can sanely execute. */ /* Verify that we can sanely execute. */
ams::CheckApiVersion(); ams::CheckApiVersion();
} }
@@ -50,11 +60,23 @@ namespace ams {
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main)); os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main)); AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main));
/* Initialize htcs. */ bool use_htcs = false, use_tcp = false;
constexpr auto HtcsSocketCountMax = 8; {
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax); R_ABORT_UNLESS(::setsysInitialize());
AMS_ABORT_UNLESS(sizeof(dmnt::g_htcs_buffer) >= buffer_size); ON_SCOPE_EXIT { ::setsysExit(); };
htcs::InitializeForSystem(dmnt::g_htcs_buffer, buffer_size, HtcsSocketCountMax);
use_htcs = IsHtcEnabled();
use_tcp = IsStandaloneGdbstubEnabled();
}
/* Initialize transport layer. */
if (use_htcs) {
dmnt::transport::InitializeByHtcs();
} else if (use_tcp) {
dmnt::transport::InitializeByTcp();
} else {
return;
}
/* Initialize debug log thread. */ /* Initialize debug log thread. */
dmnt::InitializeDebugLog(); dmnt::InitializeDebugLog();

View File

@@ -26,6 +26,7 @@ namespace ams::dmnt {
char m_name[PathLengthMax]; char m_name[PathLengthMax];
u64 m_address; u64 m_address;
u64 m_size; u64 m_size;
size_t m_name_start;
public: public:
constexpr ModuleDefinition() : m_name(), m_address(), m_size() { /* ... */ } constexpr ModuleDefinition() : m_name(), m_address(), m_size() { /* ... */ }
constexpr ~ModuleDefinition() { /* ... */ } constexpr ~ModuleDefinition() { /* ... */ }
@@ -34,9 +35,10 @@ namespace ams::dmnt {
constexpr ModuleDefinition &operator=(const ModuleDefinition &rhs) = default; constexpr ModuleDefinition &operator=(const ModuleDefinition &rhs) = default;
constexpr void Reset() { constexpr void Reset() {
m_name[0] = 0; m_name[0] = 0;
m_address = 0; m_address = 0;
m_size = 0; m_size = 0;
m_name_start = 0;
} }
constexpr bool operator==(const ModuleDefinition &rhs) const { constexpr bool operator==(const ModuleDefinition &rhs) const {
@@ -48,7 +50,7 @@ namespace ams::dmnt {
} }
constexpr char *GetNameBuffer() { return m_name; } constexpr char *GetNameBuffer() { return m_name; }
constexpr const char *GetName() const { return m_name; } constexpr const char *GetName() const { return m_name + m_name_start; }
constexpr u64 GetAddress() const { return m_address; } constexpr u64 GetAddress() const { return m_address; }
constexpr u64 GetSize() const { return m_size; } constexpr u64 GetSize() const { return m_size; }
@@ -57,6 +59,10 @@ namespace ams::dmnt {
m_address = address; m_address = address;
m_size = size; m_size = size;
} }
constexpr void SetNameStart(size_t offset) {
m_name_start = offset;
}
}; };
} }

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "dmnt2_transport_layer.hpp"
namespace ams::dmnt::transport {
namespace {
enum SocketMode {
SocketMode_Invalid,
SocketMode_Htcs,
SocketMode_Tcp,
};
constexpr inline const u16 ListenPort_GdbServer = 22225;
constexpr inline const u16 ListenPort_GdbDebugLog = 22227;
constinit os::SdkMutex g_socket_init_mutex;
constinit SocketMode g_socket_mode = SocketMode_Invalid;
constexpr inline size_t RequiredAlignment = std::max(os::ThreadStackAlignment, os::MemoryPageSize);
using SocketConfigType = socket::SystemConfigLightDefault;
/* TODO: If we ever use resolvers, increase this. */
constexpr inline size_t SocketAllocatorSize = 4_KB;
constexpr inline size_t SocketMemoryPoolSize = util::AlignUp(SocketConfigType::PerTcpSocketWorstCaseMemoryPoolSize + SocketConfigType::PerUdpSocketWorstCaseMemoryPoolSize, os::MemoryPageSize);
constexpr inline size_t SocketRequiredSize = util::AlignUp(SocketMemoryPoolSize + SocketAllocatorSize, os::MemoryPageSize);
/* Declare the memory pool. */
alignas(RequiredAlignment) constinit u8 g_socket_memory[SocketRequiredSize];
constexpr inline const SocketConfigType SocketConfig(g_socket_memory, SocketRequiredSize, SocketAllocatorSize, 2);
}
void InitializeByHtcs() {
std::scoped_lock lk(g_socket_init_mutex);
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
constexpr auto HtcsSocketCountMax = 8;
const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
AMS_ABORT_UNLESS(sizeof(g_socket_memory) >= buffer_size);
htcs::InitializeForSystem(g_socket_memory, sizeof(g_socket_memory), HtcsSocketCountMax);
g_socket_mode = SocketMode_Htcs;
}
void InitializeByTcp() {
std::scoped_lock lk(g_socket_init_mutex);
AMS_ABORT_UNLESS(g_socket_mode == SocketMode_Invalid);
R_ABORT_UNLESS(socket::Initialize(SocketConfig));
g_socket_mode = SocketMode_Tcp;
}
s32 Socket() {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Socket();
case SocketMode_Tcp: return socket::Socket(socket::Family::Af_Inet, socket::Type::Sock_Stream, socket::Protocol::IpProto_Tcp);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 Close(s32 desc) {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Close(desc);
case SocketMode_Tcp: return socket::Close(desc);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 Bind(s32 desc, PortName port_name) {
switch (g_socket_mode) {
case SocketMode_Htcs:
{
htcs::SockAddrHtcs addr;
addr.family = htcs::HTCS_AF_HTCS;
addr.peer_name = htcs::GetPeerNameAny();
switch (port_name) {
case PortName_GdbServer: std::strcpy(addr.port_name.name, "iywys@$gdb"); break;
case PortName_GdbDebugLog: std::strcpy(addr.port_name.name, "iywys@$dmnt2_log"); break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
return htcs::Bind(desc, std::addressof(addr));
}
break;
case SocketMode_Tcp:
{
socket::SockAddrIn addr = {};
addr.sin_family = socket::Family::Af_Inet;
addr.sin_addr.s_addr = socket::InAddr_Any;
switch (port_name){
case PortName_GdbServer: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbServer)); break;
case PortName_GdbDebugLog: addr.sin_port = socket::InetHtons(static_cast<u16>(ListenPort_GdbDebugLog)); break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
return socket::Bind(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), sizeof(addr));
}
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 Listen(s32 desc, s32 backlog_count) {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Listen(desc, backlog_count);
case SocketMode_Tcp: return socket::Listen(desc, backlog_count);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 Accept(s32 desc) {
switch (g_socket_mode) {
case SocketMode_Htcs:
{
htcs::SockAddrHtcs addr;
addr.family = htcs::HTCS_AF_HTCS;
addr.peer_name = htcs::GetPeerNameAny();
addr.port_name.name[0] = '\x00';
return htcs::Accept(desc, std::addressof(addr));
}
break;
case SocketMode_Tcp:
{
socket::SockAddrIn addr = {};
socket::SockLenT addr_len = sizeof(addr);
return socket::Accept(desc, reinterpret_cast<socket::SockAddr *>(std::addressof(addr)), std::addressof(addr_len));
}
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 Shutdown(s32 desc) {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Shutdown(desc, htcs::HTCS_SHUT_RDWR);
case SocketMode_Tcp: return socket::Shutdown(desc, socket::ShutdownMethod::Shut_RdWr);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags) {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Recv(desc, buffer, buffer_size, flags);
case SocketMode_Tcp: return socket::Recv(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags) {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::Send(desc, buffer, buffer_size, flags);
case SocketMode_Tcp: return socket::Send(desc, buffer, buffer_size, static_cast<socket::MsgFlag>(flags));
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
s32 GetLastError() {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::GetLastError();
case SocketMode_Tcp: return static_cast<s32>(socket::GetLastError());
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
bool IsLastErrorEAgain() {
switch (g_socket_mode) {
case SocketMode_Htcs: return htcs::GetLastError() == htcs::HTCS_EAGAIN;
case SocketMode_Tcp: return socket::GetLastError() == socket::Errno::EAgain;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::dmnt::transport {
void InitializeByHtcs();
void InitializeByTcp();
enum PortName {
PortName_GdbServer,
PortName_GdbDebugLog,
};
s32 Socket();
s32 Close(s32 desc);
s32 Bind(s32 desc, PortName port_name);
s32 Listen(s32 desc, s32 backlog_count);
s32 Accept(s32 desc);
s32 Shutdown(s32 desc);
ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags);
ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags);
s32 GetLastError();
bool IsLastErrorEAgain();
}

View File

@@ -14,11 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_htcs_receive_buffer.hpp" #include "dmnt2_transport_receive_buffer.hpp"
namespace ams::dmnt { namespace ams::dmnt {
ssize_t HtcsReceiveBuffer::Read(void *dst, size_t size) { ssize_t TransportReceiveBuffer::Read(void *dst, size_t size) {
/* Acquire exclusive access to ourselves. */ /* Acquire exclusive access to ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@@ -50,7 +50,7 @@ namespace ams::dmnt {
return readable; return readable;
} }
ssize_t HtcsReceiveBuffer::Write(const void *src, size_t size) { ssize_t TransportReceiveBuffer::Write(const void *src, size_t size) {
/* Acquire exclusive access to ourselves. */ /* Acquire exclusive access to ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@@ -71,7 +71,7 @@ namespace ams::dmnt {
return size; return size;
} }
bool HtcsReceiveBuffer::WaitToBeReadable() { bool TransportReceiveBuffer::WaitToBeReadable() {
/* Check if we're already readable. */ /* Check if we're already readable. */
{ {
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@@ -91,7 +91,7 @@ namespace ams::dmnt {
return this->IsValid(); return this->IsValid();
} }
bool HtcsReceiveBuffer::WaitToBeReadable(TimeSpan timeout) { bool TransportReceiveBuffer::WaitToBeReadable(TimeSpan timeout) {
/* Check if we're already readable. */ /* Check if we're already readable. */
{ {
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@@ -111,7 +111,7 @@ namespace ams::dmnt {
return res && this->IsValid(); return res && this->IsValid();
} }
bool HtcsReceiveBuffer::WaitToBeWritable() { bool TransportReceiveBuffer::WaitToBeWritable() {
/* Check if we're already writable. */ /* Check if we're already writable. */
{ {
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);
@@ -131,7 +131,7 @@ namespace ams::dmnt {
return this->IsValid(); return this->IsValid();
} }
void HtcsReceiveBuffer::Invalidate() { void TransportReceiveBuffer::Invalidate() {
/* Acquire exclusive access to ourselves. */ /* Acquire exclusive access to ourselves. */
std::scoped_lock lk(m_mutex); std::scoped_lock lk(m_mutex);

View File

@@ -18,7 +18,7 @@
namespace ams::dmnt { namespace ams::dmnt {
class HtcsReceiveBuffer { class TransportReceiveBuffer {
public: public:
static constexpr size_t ReceiveBufferSize = 4_KB; static constexpr size_t ReceiveBufferSize = 4_KB;
private: private:
@@ -30,7 +30,7 @@ namespace ams::dmnt {
size_t m_offset; size_t m_offset;
bool m_valid; bool m_valid;
public: public:
HtcsReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ } TransportReceiveBuffer() : m_readable_event(os::EventClearMode_ManualClear), m_writable_event(os::EventClearMode_ManualClear), m_mutex(), m_readable_size(), m_offset(), m_valid(true) { /* ... */ }
ALWAYS_INLINE bool IsReadable() const { return m_readable_size != 0; } ALWAYS_INLINE bool IsReadable() const { return m_readable_size != 0; }
ALWAYS_INLINE bool IsWritable() const { return m_readable_size == 0; } ALWAYS_INLINE bool IsWritable() const { return m_readable_size == 0; }

View File

@@ -14,12 +14,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_htcs_session.hpp" #include "dmnt2_transport_layer.hpp"
#include "dmnt2_transport_session.hpp"
#include "dmnt2_debug_log.hpp" #include "dmnt2_debug_log.hpp"
namespace ams::dmnt { namespace ams::dmnt {
HtcsSession::HtcsSession(int fd) : m_socket(fd), m_valid(true) { TransportSession::TransportSession(int fd) : m_socket(fd), m_valid(true) {
/* Create our thread. */ /* Create our thread. */
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_receive_thread), ReceiveThreadEntry, this, m_receive_thread_stack, sizeof(m_receive_thread_stack), os::HighestThreadPriority - 1)); R_ABORT_UNLESS(os::CreateThread(std::addressof(m_receive_thread), ReceiveThreadEntry, this, m_receive_thread_stack, sizeof(m_receive_thread_stack), os::HighestThreadPriority - 1));
@@ -30,7 +31,7 @@ namespace ams::dmnt {
AMS_DMNT2_GDB_LOG_INFO("Created Session %d\n", m_socket); AMS_DMNT2_GDB_LOG_INFO("Created Session %d\n", m_socket);
} }
HtcsSession::~HtcsSession() { TransportSession::~TransportSession() {
/* Note that we connected. */ /* Note that we connected. */
AMS_DMNT2_GDB_LOG_INFO("Closing Session %d\n", m_socket); AMS_DMNT2_GDB_LOG_INFO("Closing Session %d\n", m_socket);
@@ -38,25 +39,25 @@ namespace ams::dmnt {
m_receive_buffer.Invalidate(); m_receive_buffer.Invalidate();
/* Shutdown our socket. */ /* Shutdown our socket. */
htcs::Shutdown(m_socket, htcs::HTCS_SHUT_RDWR); transport::Shutdown(m_socket);
/* Wait for our thread. */ /* Wait for our thread. */
os::WaitThread(std::addressof(m_receive_thread)); os::WaitThread(std::addressof(m_receive_thread));
os::DestroyThread(std::addressof(m_receive_thread)); os::DestroyThread(std::addressof(m_receive_thread));
/* Close our socket. */ /* Close our socket. */
htcs::Close(m_socket); transport::Close(m_socket);
} }
bool HtcsSession::WaitToBeReadable() { bool TransportSession::WaitToBeReadable() {
return m_receive_buffer.WaitToBeReadable(); return m_receive_buffer.WaitToBeReadable();
} }
bool HtcsSession::WaitToBeReadable(TimeSpan timeout) { bool TransportSession::WaitToBeReadable(TimeSpan timeout) {
return m_receive_buffer.WaitToBeReadable(timeout); return m_receive_buffer.WaitToBeReadable(timeout);
} }
util::optional<char> HtcsSession::GetChar() { util::optional<char> TransportSession::GetChar() {
/* Wait for us to have data. */ /* Wait for us to have data. */
m_receive_buffer.WaitToBeReadable(); m_receive_buffer.WaitToBeReadable();
@@ -69,9 +70,9 @@ namespace ams::dmnt {
} }
} }
ssize_t HtcsSession::PutChar(char c) { ssize_t TransportSession::PutChar(char c) {
/* Send the character. */ /* Send the character. */
const auto sent = htcs::Send(m_socket, std::addressof(c), sizeof(c), 0); const auto sent = transport::Send(m_socket, std::addressof(c), sizeof(c), 0);
if (sent < 0) { if (sent < 0) {
m_valid = false; m_valid = false;
} }
@@ -79,13 +80,13 @@ namespace ams::dmnt {
return sent; return sent;
} }
ssize_t HtcsSession::PutString(const char *str) { ssize_t TransportSession::PutString(const char *str) {
/* Repeatedly send until all is sent. */ /* Repeatedly send until all is sent. */
const size_t len = std::strlen(str); const size_t len = std::strlen(str);
size_t remaining = len; size_t remaining = len;
while (remaining > 0) { while (remaining > 0) {
const auto sent = htcs::Send(m_socket, str, remaining, 0); const auto sent = transport::Send(m_socket, str, remaining, 0);
if (sent >= 0) { if (sent >= 0) {
remaining -= sent; remaining -= sent;
str += sent; str += sent;
@@ -98,22 +99,22 @@ namespace ams::dmnt {
return len; return len;
} }
void HtcsSession::ReceiveThreadFunction() { void TransportSession::ReceiveThreadFunction() {
/* Create temporary buffer. */ /* Create temporary buffer. */
u8 buffer[HtcsReceiveBuffer::ReceiveBufferSize]; u8 buffer[TransportReceiveBuffer::ReceiveBufferSize];
/* Loop receiving data. */ /* Loop receiving data. */
while (true) { while (true) {
/* Receive data. */ /* Receive data. */
const auto res = htcs::Recv(m_socket, buffer, sizeof(buffer), 0); const auto res = transport::Recv(m_socket, buffer, sizeof(buffer), 0);
if (res > 0) { if (res > 0) {
/* Write the data to our buffer. */ /* Write the data to our buffer. */
m_receive_buffer.WaitToBeWritable(); m_receive_buffer.WaitToBeWritable();
m_receive_buffer.Write(buffer, res); m_receive_buffer.Write(buffer, res);
} else { } else {
/* Otherwise, if we got an error other than "try again", we're done. */ /* Otherwise, if we got an error other than "try again", we're done. */
if (htcs::GetLastError() != htcs::HTCS_EAGAIN) { if (!transport::IsLastErrorEAgain()) {
AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(htcs::GetLastError())); AMS_DMNT2_GDB_LOG_INFO("Session %d invalid, res=%ld, err=%d\n", m_socket, res, static_cast<int>(transport::GetLastError()));
m_valid = false; m_valid = false;
break; break;
} }

View File

@@ -15,20 +15,20 @@
*/ */
#pragma once #pragma once
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "dmnt2_htcs_receive_buffer.hpp" #include "dmnt2_transport_receive_buffer.hpp"
namespace ams::dmnt { namespace ams::dmnt {
class HtcsSession { class TransportSession {
private: private:
alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + HtcsReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)]; alignas(os::ThreadStackAlignment) u8 m_receive_thread_stack[util::AlignUp(os::MemoryPageSize + TransportReceiveBuffer::ReceiveBufferSize, os::ThreadStackAlignment)];
HtcsReceiveBuffer m_receive_buffer; TransportReceiveBuffer m_receive_buffer;
os::ThreadType m_receive_thread; os::ThreadType m_receive_thread;
int m_socket; int m_socket;
bool m_valid; bool m_valid;
public: public:
HtcsSession(int fd); TransportSession(int fd);
~HtcsSession(); ~TransportSession();
ALWAYS_INLINE bool IsValid() const { return m_valid; } ALWAYS_INLINE bool IsValid() const { return m_valid; }
@@ -41,7 +41,7 @@ namespace ams::dmnt {
private: private:
static void ReceiveThreadEntry(void *arg) { static void ReceiveThreadEntry(void *arg) {
static_cast<HtcsSession *>(arg)->ReceiveThreadFunction(); static_cast<TransportSession *>(arg)->ReceiveThreadFunction();
} }
void ReceiveThreadFunction(); void ReceiveThreadFunction();

View File

@@ -248,7 +248,6 @@ namespace ams::dmnt::cheat::impl {
void StartProcess(os::ProcessId process_id) const { void StartProcess(os::ProcessId process_id) const {
R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id)); R_ABORT_UNLESS(pm::dmnt::StartProcess(process_id));
} }
public: public:
CheatProcessManager() : m_cheat_lock(), m_unsafe_break_event(os::EventClearMode_ManualClear), m_debug_events_event(os::EventClearMode_AutoClear), m_cheat_process_event(os::EventClearMode_AutoClear, true) { CheatProcessManager() : m_cheat_lock(), m_unsafe_break_event(os::EventClearMode_ManualClear), m_debug_events_event(os::EventClearMode_AutoClear), m_cheat_process_event(os::EventClearMode_AutoClear, true) {
/* Learn whether we should enable cheats by default. */ /* Learn whether we should enable cheats by default. */