mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 01:26:34 +00:00
kern/dmnt2: allow retrieval of process info via extension
This also fixes ctrl-c break in gdbstub, and fixes crash on unknown monitor cmd.
This commit is contained in:
parent
9011384dbe
commit
d2b024f19f
5 changed files with 214 additions and 78 deletions
|
@ -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. */
|
||||||
|
|
|
@ -38,36 +38,7 @@ namespace ams::kern::svc {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
Result GetInfoImpl(u64 *out, ams::svc::InfoType info_type, KProcess *process) {
|
||||||
switch (info_type) {
|
|
||||||
case ams::svc::InfoType_CoreMask:
|
|
||||||
case ams::svc::InfoType_PriorityMask:
|
|
||||||
case ams::svc::InfoType_AliasRegionAddress:
|
|
||||||
case ams::svc::InfoType_AliasRegionSize:
|
|
||||||
case ams::svc::InfoType_HeapRegionAddress:
|
|
||||||
case ams::svc::InfoType_HeapRegionSize:
|
|
||||||
case ams::svc::InfoType_TotalMemorySize:
|
|
||||||
case ams::svc::InfoType_UsedMemorySize:
|
|
||||||
case ams::svc::InfoType_AslrRegionAddress:
|
|
||||||
case ams::svc::InfoType_AslrRegionSize:
|
|
||||||
case ams::svc::InfoType_StackRegionAddress:
|
|
||||||
case ams::svc::InfoType_StackRegionSize:
|
|
||||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
|
||||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
|
||||||
case ams::svc::InfoType_ProgramId:
|
|
||||||
case ams::svc::InfoType_UserExceptionContextAddress:
|
|
||||||
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
|
||||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
|
||||||
case ams::svc::InfoType_IsApplication:
|
|
||||||
case ams::svc::InfoType_FreeThreadCount:
|
|
||||||
{
|
|
||||||
/* These info types don't support non-zero subtypes. */
|
|
||||||
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
|
||||||
|
|
||||||
/* Get the process from its handle. */
|
|
||||||
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
|
|
||||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
|
||||||
|
|
||||||
switch (info_type) {
|
switch (info_type) {
|
||||||
case ams::svc::InfoType_CoreMask:
|
case ams::svc::InfoType_CoreMask:
|
||||||
*out = process->GetCoreMask();
|
*out = process->GetCoreMask();
|
||||||
|
@ -137,6 +108,66 @@ namespace ams::kern::svc {
|
||||||
break;
|
break;
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||||
|
switch (info_type) {
|
||||||
|
case ams::svc::InfoType_CoreMask:
|
||||||
|
case ams::svc::InfoType_PriorityMask:
|
||||||
|
case ams::svc::InfoType_AliasRegionAddress:
|
||||||
|
case ams::svc::InfoType_AliasRegionSize:
|
||||||
|
case ams::svc::InfoType_HeapRegionAddress:
|
||||||
|
case ams::svc::InfoType_HeapRegionSize:
|
||||||
|
case ams::svc::InfoType_TotalMemorySize:
|
||||||
|
case ams::svc::InfoType_UsedMemorySize:
|
||||||
|
case ams::svc::InfoType_AslrRegionAddress:
|
||||||
|
case ams::svc::InfoType_AslrRegionSize:
|
||||||
|
case ams::svc::InfoType_StackRegionAddress:
|
||||||
|
case ams::svc::InfoType_StackRegionSize:
|
||||||
|
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||||
|
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||||
|
case ams::svc::InfoType_ProgramId:
|
||||||
|
case ams::svc::InfoType_UserExceptionContextAddress:
|
||||||
|
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
||||||
|
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||||
|
case ams::svc::InfoType_IsApplication:
|
||||||
|
case ams::svc::InfoType_FreeThreadCount:
|
||||||
|
{
|
||||||
|
/* These info types don't support non-zero subtypes. */
|
||||||
|
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||||
|
|
||||||
|
/* Get the process from its 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());
|
||||||
|
|
||||||
|
/* Return the relevant info. */
|
||||||
|
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::InfoType_DebuggerAttached:
|
case ams::svc::InfoType_DebuggerAttached:
|
||||||
|
|
|
@ -47,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +231,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,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()) {
|
||||||
|
@ -108,6 +119,20 @@ namespace ams::dmnt {
|
||||||
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, bool start_process = false);
|
Result Attach(os::ProcessId process_id, bool start_process = false);
|
||||||
void Detach();
|
void Detach();
|
||||||
|
@ -152,6 +177,8 @@ namespace ams::dmnt {
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1209,6 +1209,11 @@ namespace ams::dmnt {
|
||||||
/* Send packet. */
|
/* Send packet. */
|
||||||
this->SendPacket(std::addressof(do_break), reply_buffer);
|
this->SendPacket(std::addressof(do_break), reply_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we should, break the process. */
|
||||||
|
if (do_break) {
|
||||||
|
m_debug_process.Break();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1855,7 +1860,9 @@ namespace ams::dmnt {
|
||||||
|
|
||||||
void GdbServerImpl::qRcmd() {
|
void GdbServerImpl::qRcmd() {
|
||||||
/* Decode the command. */
|
/* Decode the command. */
|
||||||
HexToMemory(m_buffer, m_receive_packet, std::strlen(m_receive_packet));
|
const auto packet_len = std::strlen(m_receive_packet);
|
||||||
|
HexToMemory(m_buffer, m_receive_packet, packet_len);
|
||||||
|
m_buffer[packet_len / 2] = '\x00';
|
||||||
|
|
||||||
/* Convert our response to hex, on complete. */
|
/* Convert our response to hex, on complete. */
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
|
@ -1866,26 +1873,39 @@ namespace ams::dmnt {
|
||||||
/* Parse the command. */
|
/* Parse the command. */
|
||||||
char *command = reinterpret_cast<char *>(m_buffer);
|
char *command = reinterpret_cast<char *>(m_buffer);
|
||||||
if (ParsePrefix(command, "help")) {
|
if (ParsePrefix(command, "help")) {
|
||||||
SetReply(m_buffer, "get base\n"
|
SetReply(m_buffer, "get info\n"
|
||||||
"wait application\n"
|
"wait application\n"
|
||||||
"wait {program id}\n"
|
"wait {program id}\n"
|
||||||
"wait homebrew\n");
|
"wait homebrew\n");
|
||||||
} else if (ParsePrefix(command, "get base") || ParsePrefix(command, "get modules")) {
|
} else if (ParsePrefix(command, "get base") || ParsePrefix(command, "get info") || ParsePrefix(command, "get modules")) {
|
||||||
SetReply(m_buffer, "Modules:\n");
|
|
||||||
|
|
||||||
if (!this->HasDebugProcess()) {
|
if (!this->HasDebugProcess()) {
|
||||||
AppendReply(m_buffer, " [Not Attached]\n");
|
SetReply(m_buffer, "Not attached.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetReply(m_buffer, "Process: 0x%lx (%s)\n"
|
||||||
|
"Program Id: 0x%016lx\n"
|
||||||
|
"Application: %d\n"
|
||||||
|
"Hbl: %d\n"
|
||||||
|
"Layout:\n", m_process_id.value, m_debug_process.GetProcessName(), m_debug_process.GetProgramLocation().program_id.value, m_debug_process.IsApplication(), m_debug_process.GetOverrideStatus().IsHbl());
|
||||||
|
|
||||||
|
AppendReply(m_buffer, " Alias: 0x%010lx - 0x%010lx\n"
|
||||||
|
" Heap: 0x%010lx - 0x%010lx\n"
|
||||||
|
" Aslr: 0x%010lx - 0x%010lx\n"
|
||||||
|
" Stack: 0x%010lx - 0x%010lx\n"
|
||||||
|
"Modules:\n", m_debug_process.GetAliasRegionAddress(), m_debug_process.GetAliasRegionAddress() + m_debug_process.GetAliasRegionSize() - 1,
|
||||||
|
m_debug_process.GetHeapRegionAddress(), m_debug_process.GetHeapRegionAddress() + m_debug_process.GetHeapRegionSize() - 1,
|
||||||
|
m_debug_process.GetAslrRegionAddress(), m_debug_process.GetAslrRegionAddress() + m_debug_process.GetAslrRegionSize() - 1,
|
||||||
|
m_debug_process.GetStackRegionAddress(), m_debug_process.GetStackRegionAddress() + m_debug_process.GetStackRegionSize() - 1);
|
||||||
|
|
||||||
/* Get the module list. */
|
/* Get the module list. */
|
||||||
for (size_t i = 0; i < m_debug_process.GetModuleCount(); ++i) {
|
for (size_t i = 0; i < m_debug_process.GetModuleCount(); ++i) {
|
||||||
const char *module_name = m_debug_process.GetModuleName(i);
|
const char *module_name = m_debug_process.GetModuleName(i);
|
||||||
const auto name_len = std::strlen(module_name);
|
const auto name_len = std::strlen(module_name);
|
||||||
if (name_len < 5 || (std::strcmp(module_name + name_len - 4, ".elf") != 0 && std::strcmp(module_name + name_len - 4, ".nss") != 0)) {
|
if (name_len < 5 || (std::strcmp(module_name + name_len - 4, ".elf") != 0 && std::strcmp(module_name + name_len - 4, ".nss") != 0)) {
|
||||||
AppendReply(m_buffer, " %p - %p %s.elf\n", reinterpret_cast<void *>(m_debug_process.GetModuleBaseAddress(i)), reinterpret_cast<void *>(m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1), module_name);
|
AppendReply(m_buffer, " 0x%010lx - 0x%010lx %s.elf\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name);
|
||||||
} else {
|
} else {
|
||||||
AppendReply(m_buffer, " %p - %p %s\n", reinterpret_cast<void *>(m_debug_process.GetModuleBaseAddress(i)), reinterpret_cast<void *>(m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1), module_name);
|
AppendReply(m_buffer, " 0x%010lx - 0x%010lx %s\n", m_debug_process.GetModuleBaseAddress(i), m_debug_process.GetModuleBaseAddress(i) + m_debug_process.GetModuleSize(i) - 1, module_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ParsePrefix(command, "wait application") || ParsePrefix(command, "wait app")) {
|
} else if (ParsePrefix(command, "wait application") || ParsePrefix(command, "wait app")) {
|
||||||
|
@ -1916,7 +1936,8 @@ namespace ams::dmnt {
|
||||||
|
|
||||||
SetReply(m_buffer, "[TODO] wait for program id 0x%lx\n", program_id);
|
SetReply(m_buffer, "[TODO] wait for program id 0x%lx\n", program_id);
|
||||||
} else {
|
} else {
|
||||||
SetReply(m_buffer, "Unknown command `%s`\n", command);
|
SetReply(m_reply_packet, "Unknown command `%s`\n", command);
|
||||||
|
std::memcpy(m_buffer, m_reply_packet, std::strlen(m_reply_packet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue