diff --git a/k11_extension/include/globals.h b/k11_extension/include/globals.h index f197f0f..c8cb4f2 100644 --- a/k11_extension/include/globals.h +++ b/k11_extension/include/globals.h @@ -132,6 +132,7 @@ typedef struct CfwInfo } CfwInfo; extern CfwInfo cfwInfo; +extern u32 kextBasePa; extern vu32 rosalinaState; extern bool hasStartedRosalinaNetworkFuncsOnce; diff --git a/k11_extension/source/globals.c b/k11_extension/source/globals.c index c6e2947..1d8f7fb 100644 --- a/k11_extension/source/globals.c +++ b/k11_extension/source/globals.c @@ -108,6 +108,7 @@ void (*mcuReboot)(void); void (*coreBarrier)(void); CfwInfo cfwInfo; +u32 kextBasePa; vu32 rosalinaState; bool hasStartedRosalinaNetworkFuncsOnce; diff --git a/k11_extension/source/main.c b/k11_extension/source/main.c index 5fcaf0d..c069188 100644 --- a/k11_extension/source/main.c +++ b/k11_extension/source/main.c @@ -271,6 +271,7 @@ void main(FcramLayout *layout, KCoreContext *ctxs) memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16); exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20)); cfwInfo = p->cfwInfo; + kextBasePa = p->basePA; memcpy(originalHandlers + 1, p->originalHandlers, 16); void **arm11SvcTable = (void**)originalHandlers[2]; diff --git a/k11_extension/source/svc/GetSystemInfo.c b/k11_extension/source/svc/GetSystemInfo.c index 5b1cf42..4a5f88f 100644 --- a/k11_extension/source/svc/GetSystemInfo.c +++ b/k11_extension/source/svc/GetSystemInfo.c @@ -79,7 +79,7 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param) break; case 0x300: // K11Ext size - *out = (s64)(__end__ - __start__); + *out = (s64)(((u64)kextBasePa << 32) | (u64)(__end__ - __start__)); break; default: diff --git a/sysmodules/rosalina/include/menus.h b/sysmodules/rosalina/include/menus.h index 1764420..88fede1 100644 --- a/sysmodules/rosalina/include/menus.h +++ b/sysmodules/rosalina/include/menus.h @@ -39,3 +39,6 @@ void RosalinaMenu_ProcessList(void); void RosalinaMenu_PowerOff(void); void RosalinaMenu_Reboot(void); void RosalinaMenu_Cheats(void); + +bool rosalinaMenuShouldShowDebugInfo(void); +void RosalinaMenu_ShowDebugInfo(void); diff --git a/sysmodules/rosalina/include/utils.h b/sysmodules/rosalina/include/utils.h index ae51b9e..8c1a6a1 100644 --- a/sysmodules/rosalina/include/utils.h +++ b/sysmodules/rosalina/include/utils.h @@ -62,3 +62,7 @@ static inline bool isServiceUsable(const char *name) bool 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); diff --git a/sysmodules/rosalina/source/gdb/remote_command.c b/sysmodules/rosalina/source/gdb/remote_command.c index 9471f7c..11270d7 100644 --- a/sysmodules/rosalina/source/gdb/remote_command.c +++ b/sysmodules/rosalina/source/gdb/remote_command.c @@ -11,6 +11,8 @@ #include "fmt.h" #include "gdb/breakpoints.h" +#include "../utils.h" + struct { const char *name; @@ -208,84 +210,19 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig) 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) { - u32 address = 0; u32 posInBuffer = 0; - u32 maxPosInBuffer = GDB_BUF_LEN / 2 - 35; ///< 35 is the maximum length of a formatted region Handle handle; - MemInfo memi; - PageInfo pagei; char outbuf[GDB_BUF_LEN / 2 + 1]; if(R_FAILED(svcOpenProcess(&handle, ctx->pid))) { posInBuffer = sprintf(outbuf, "Invalid process (wtf?)\n"); - goto end; + return GDB_SendHexPacket(ctx, outbuf, posInBuffer); } - 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) - { - 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: + posInBuffer = formatMemoryMapOfProcess(outbuf, GDB_BUF_LEN / 2, handle); return GDB_SendHexPacket(ctx, outbuf, posInBuffer); } diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c index 57c4584..1103e3b 100644 --- a/sysmodules/rosalina/source/menus.c +++ b/sysmodules/rosalina/source/menus.c @@ -55,10 +55,44 @@ Menu rosalinaMenu = { { "Power off", METHOD, .method = &RosalinaMenu_PowerOff }, { "Reboot", METHOD, .method = &RosalinaMenu_Reboot }, { "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) { Draw_Lock(); diff --git a/sysmodules/rosalina/source/utils.c b/sysmodules/rosalina/source/utils.c new file mode 100644 index 0000000..9719896 --- /dev/null +++ b/sysmodules/rosalina/source/utils.c @@ -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 . +* +* 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 +#include + +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; +}