rosalina: add hidden debug info menu

This commit is contained in:
TuxSH 2020-05-17 22:48:26 +01:00
parent 9097276a06
commit b02d0346fd
9 changed files with 159 additions and 68 deletions

View File

@ -132,6 +132,7 @@ typedef struct CfwInfo
} CfwInfo; } CfwInfo;
extern CfwInfo cfwInfo; extern CfwInfo cfwInfo;
extern u32 kextBasePa;
extern vu32 rosalinaState; extern vu32 rosalinaState;
extern bool hasStartedRosalinaNetworkFuncsOnce; extern bool hasStartedRosalinaNetworkFuncsOnce;

View File

@ -108,6 +108,7 @@ void (*mcuReboot)(void);
void (*coreBarrier)(void); void (*coreBarrier)(void);
CfwInfo cfwInfo; CfwInfo cfwInfo;
u32 kextBasePa;
vu32 rosalinaState; vu32 rosalinaState;
bool hasStartedRosalinaNetworkFuncsOnce; bool hasStartedRosalinaNetworkFuncsOnce;

View File

@ -271,6 +271,7 @@ void main(FcramLayout *layout, KCoreContext *ctxs)
memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16); memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16);
exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20)); exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20));
cfwInfo = p->cfwInfo; cfwInfo = p->cfwInfo;
kextBasePa = p->basePA;
memcpy(originalHandlers + 1, p->originalHandlers, 16); memcpy(originalHandlers + 1, p->originalHandlers, 16);
void **arm11SvcTable = (void**)originalHandlers[2]; void **arm11SvcTable = (void**)originalHandlers[2];

View File

@ -79,7 +79,7 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
break; break;
case 0x300: // K11Ext size case 0x300: // K11Ext size
*out = (s64)(__end__ - __start__); *out = (s64)(((u64)kextBasePa << 32) | (u64)(__end__ - __start__));
break; break;
default: default:

View File

@ -39,3 +39,6 @@ void RosalinaMenu_ProcessList(void);
void RosalinaMenu_PowerOff(void); void RosalinaMenu_PowerOff(void);
void RosalinaMenu_Reboot(void); void RosalinaMenu_Reboot(void);
void RosalinaMenu_Cheats(void); void RosalinaMenu_Cheats(void);
bool rosalinaMenuShouldShowDebugInfo(void);
void RosalinaMenu_ShowDebugInfo(void);

View File

@ -62,3 +62,7 @@ static inline bool isServiceUsable(const char *name)
bool r; bool r;
return R_SUCCEEDED(srvIsServiceRegistered(&r, name)) && r; return R_SUCCEEDED(srvIsServiceRegistered(&r, name)) && r;
} }
void formatMemoryPermission(char *outbuf, MemPerm perm);
void formatUserMemoryState(char *outbuf, MemState state);
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle);

View File

@ -11,6 +11,8 @@
#include "fmt.h" #include "fmt.h"
#include "gdb/breakpoints.h" #include "gdb/breakpoints.h"
#include "../utils.h"
struct struct
{ {
const char *name; const char *name;
@ -208,84 +210,19 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig)
return GDB_SendHexPacket(ctx, outbuf, n); return GDB_SendHexPacket(ctx, outbuf, n);
} }
static const char *FormatMemPerm(u32 perm)
{
if (perm == MEMPERM_DONTCARE)
return "???";
static char buf[4] = {0};
buf[0] = perm & MEMPERM_READ ? 'r' : '-';
buf[1] = perm & MEMPERM_WRITE ? 'w' : '-';
buf[2] = perm & MEMPERM_EXECUTE ? 'x' : '-';
return buf;
}
static const char *FormatMemState(u32 state)
{
if (state > 11)
return "Unknown";
static const char *states[12] =
{
"Free",
"Reserved",
"IO",
"Static",
"Code",
"Private",
"Shared",
"Continuous",
"Aliased",
"Alias",
"AliasCode",
"Locked"
};
return states[state];
}
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions) GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions)
{ {
u32 address = 0;
u32 posInBuffer = 0; u32 posInBuffer = 0;
u32 maxPosInBuffer = GDB_BUF_LEN / 2 - 35; ///< 35 is the maximum length of a formatted region
Handle handle; Handle handle;
MemInfo memi;
PageInfo pagei;
char outbuf[GDB_BUF_LEN / 2 + 1]; char outbuf[GDB_BUF_LEN / 2 + 1];
if(R_FAILED(svcOpenProcess(&handle, ctx->pid))) if(R_FAILED(svcOpenProcess(&handle, ctx->pid)))
{ {
posInBuffer = sprintf(outbuf, "Invalid process (wtf?)\n"); posInBuffer = sprintf(outbuf, "Invalid process (wtf?)\n");
goto end; return GDB_SendHexPacket(ctx, outbuf, posInBuffer);
} }
s64 TTBCR; posInBuffer = formatMemoryMapOfProcess(outbuf, GDB_BUF_LEN / 2, handle);
svcGetSystemInfo(&TTBCR, 0x10002, 0);
while (address < (1u << (32 - (u32)TTBCR)) ///< Limit to check for regions
&& posInBuffer < maxPosInBuffer
&& R_SUCCEEDED(svcQueryProcessMemory(&memi, &pagei, handle, address)))
{
// Update the address for next region
address = memi.base_addr + memi.size;
// If region isn't FREE then add it to the list
if (memi.state != MEMSTATE_FREE)
{
const char *perm = FormatMemPerm(memi.perm);
const char *state = FormatMemState(memi.state);
posInBuffer += sprintf(outbuf + posInBuffer, "%08lx - %08lx %s %s\n",
memi.base_addr, address, perm, state);
}
}
svcCloseHandle(handle);
end:
return GDB_SendHexPacket(ctx, outbuf, posInBuffer); return GDB_SendHexPacket(ctx, outbuf, posInBuffer);
} }

View File

@ -55,10 +55,44 @@ Menu rosalinaMenu = {
{ "Power off", METHOD, .method = &RosalinaMenu_PowerOff }, { "Power off", METHOD, .method = &RosalinaMenu_PowerOff },
{ "Reboot", METHOD, .method = &RosalinaMenu_Reboot }, { "Reboot", METHOD, .method = &RosalinaMenu_Reboot },
{ "Credits", METHOD, .method = &RosalinaMenu_ShowCredits }, { "Credits", METHOD, .method = &RosalinaMenu_ShowCredits },
{ "Debug info", METHOD, .method = &RosalinaMenu_ShowDebugInfo, .visibility = &rosalinaMenuShouldShowDebugInfo },
{}, {},
} }
}; };
bool rosalinaMenuShouldShowDebugInfo(void)
{
return false;
}
void RosalinaMenu_ShowDebugInfo(void)
{
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
char memoryMap[512];
formatMemoryMapOfProcess(memoryMap, 511, CUR_PROCESS_HANDLE);
s64 kextAddrSize;
svcGetSystemInfo(&kextAddrSize, 0x10000, 0x300);
u32 kextPa = (u32)((u64)kextAddrSize >> 32);
u32 kextSize = (u32)kextAddrSize;
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Debug info");
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, memoryMap);
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Kernel ext PA: %08lx - %08lx\n", kextPa, kextPa + kextSize);
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void RosalinaMenu_ShowCredits(void) void RosalinaMenu_ShowCredits(void)
{ {
Draw_Lock(); Draw_Lock();

View File

@ -0,0 +1,110 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "utils.h"
#include "csvc.h"
#include <string.h>
#include <stdio.h>
void formatMemoryPermission(char *outbuf, MemPerm perm)
{
if (perm == MEMPERM_DONTCARE)
{
strcpy(outbuf, "???");
return;
}
outbuf[0] = perm & MEMPERM_READ ? 'r' : '-';
outbuf[1] = perm & MEMPERM_WRITE ? 'w' : '-';
outbuf[2] = perm & MEMPERM_EXECUTE ? 'x' : '-';
outbuf[3] = '\0';
}
void formatUserMemoryState(char *outbuf, MemState state)
{
static const char *states[12] =
{
"Free",
"Reserved",
"IO",
"Static",
"Code",
"Private",
"Shared",
"Continuous",
"Aliased",
"Alias",
"AliasCode",
"Locked"
};
strcpy(outbuf, state > 11 ? "Unknown" : states[state]);
}
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle)
{
u32 maxLineSize = 35 + (handle == CUR_PROCESS_HANDLE ? 15 : 0);
u32 address = 0;
u32 posInBuffer = 0;
u32 maxPosInBuffer = bufLen - maxLineSize; // 35 is the maximum length of a formatted region
MemInfo memi;
PageInfo pagei;
char pabuf[32];
char permbuf[8];
char statebuf[16];
s64 TTBCR;
svcGetSystemInfo(&TTBCR, 0x10002, 0);
while (address < (1u << (32 - (u32)TTBCR)) // Limit to check for regions
&& posInBuffer < maxPosInBuffer
&& R_SUCCEEDED(svcQueryProcessMemory(&memi, &pagei, handle, address)))
{
// Update the address for next region
address = memi.base_addr + memi.size;
// If region isn't FREE then add it to the list
if (memi.state != MEMSTATE_FREE)
{
if (handle == CUR_PROCESS_HANDLE)
{
u32 pa = svcConvertVAToPA((void *)memi.base_addr, false);
sprintf(pabuf, " (PA %08lx)", pa);
}
else
pabuf[0] = '\0';
formatMemoryPermission(permbuf, memi.perm);
formatUserMemoryState(statebuf, memi.state);
posInBuffer += sprintf(outbuf + posInBuffer, "%08lx - %08lx%s %s %s\n",
memi.base_addr, address, pabuf, permbuf, statebuf);
}
}
svcCloseHandle(handle);
return posInBuffer;
}