From 56be46b4bde875e7605ea9ea3bb2e6e915bf60c9 Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Sun, 10 Apr 2022 21:43:19 +0100 Subject: [PATCH] rosalina: introduce bootdiag, tool to dump state of a process in early init --- sysmodules/rosalina/include/bootdiag.h | 30 +++++++ sysmodules/rosalina/source/bootdiag.c | 116 +++++++++++++++++++++++++ sysmodules/rosalina/source/main.c | 2 + 3 files changed, 148 insertions(+) create mode 100644 sysmodules/rosalina/include/bootdiag.h create mode 100644 sysmodules/rosalina/source/bootdiag.c diff --git a/sysmodules/rosalina/include/bootdiag.h b/sysmodules/rosalina/include/bootdiag.h new file mode 100644 index 0000000..045dbf8 --- /dev/null +++ b/sysmodules/rosalina/include/bootdiag.h @@ -0,0 +1,30 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2022 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. +*/ + +#pragma once +#include "MyThread.h" + +MyThread *bootdiagCreateThread(void); diff --git a/sysmodules/rosalina/source/bootdiag.c b/sysmodules/rosalina/source/bootdiag.c new file mode 100644 index 0000000..78192af --- /dev/null +++ b/sysmodules/rosalina/source/bootdiag.c @@ -0,0 +1,116 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2022 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 <3ds.h> +#include "MyThread.h" +#include "ifile.h" +#include "fmt.h" + +#ifdef BOOTDIAG_ENABLED + +static MyThread bootdiagThread; +static u8 ALIGN(0x1000) bootdiagThreadStack[0x1000]; + +#define BOOTDIAG_WAIT_TIME (2000 * 1000 * 1000u) // 2 seconds +#define BOOTDIAG_PID 2u // PM +#define BOOTDIAG_DUMP_TO_FILE 0 + +static int bootdiagDumpThread(char *buf, Handle debug, u32 tid) +{ + ThreadContext ctx; + if (R_FAILED(svcGetDebugThreadContext(&ctx, debug, tid, THREADCONTEXT_CONTROL_ALL))) + return 0; + + s64 dummy; + u32 mask = 0xFF; + svcGetDebugThreadParam(&dummy, &mask, debug, tid, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + + return sprintf(buf, "Thread %lu -- PC=%08lx LR=%08lx R0=%08lx sched=%lu\n", tid, ctx.cpu_registers.pc, ctx.cpu_registers.lr, ctx.cpu_registers.r[0], mask); +} + +static int bootdiagDumpProcess(char *buf, u32 pid) +{ + Handle debug = 0; + int n = 0; + + if (R_FAILED(svcDebugActiveProcess(&debug, pid))) + __builtin_trap(); + + while (svcWaitSynchronization(debug, 500 * 1000 * 1000) == 0) + { + DebugEventInfo info; + if (R_FAILED(svcGetProcessDebugEvent(&info, debug))) + break; + + if (info.type == DBGEVENT_ATTACH_THREAD) + n += bootdiagDumpThread(buf + n, debug, info.thread_id); + + if (info.flags & 1) + svcContinueDebugEvent(debug, 0); + } + + svcCloseHandle(debug); + return n; +} + +static void bootdiagThreadMain(void) +{ + char buf[512]; + + svcSleepThread(BOOTDIAG_WAIT_TIME); + int n = bootdiagDumpProcess(buf, BOOTDIAG_PID); + +#if BOOTDIAG_DUMP_TO_FILE + IFile file; + FS_ArchiveID archiveId = ARCHIVE_SDMC; + + if (R_FAILED(fsInit())) __builtin_trap(); + + IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/bootdiag.txt"), FS_OPEN_CREATE | FS_OPEN_WRITE); + u64 ttl = 0; + IFile_Write(file, &ttl, buf, (u32)n, 0); + IFile_Close(&file); + + fsExit(); +#else + (void)n; + *(volatile char *)buf; + __builtin_trap(); // use stack dump to extract info +#endif +} + +MyThread *bootdiagCreateThread(void) +{ + if(R_FAILED(MyThread_Create(&bootdiagThread, bootdiagThreadMain, bootdiagThreadStack, sizeof(bootdiagThreadStack), 18, 0))) + svcBreak(USERBREAK_PANIC); + return &bootdiagThread; +} +#endif + +MyThread *bootdiagCreateThread(void) +{ + return NULL; +} diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c index d1d102e..2357821 100644 --- a/sysmodules/rosalina/source/main.c +++ b/sysmodules/rosalina/source/main.c @@ -41,6 +41,7 @@ #include "input_redirection.h" #include "minisoc.h" #include "draw.h" +#include "bootdiag.h" #include "task_runner.h" @@ -264,6 +265,7 @@ int main(void) MyThread *menuThread = menuCreateThread(); MyThread *taskRunnerThread = taskRunnerCreateThread(); MyThread *errDispThread = errDispCreateThread(); + bootdiagCreateThread(); if (R_FAILED(ServiceManager_Run(services, notifications, NULL))) svcBreak(USERBREAK_PANIC);