mirror of
https://github.com/wiiu-env/gdbstub_plugin.git
synced 2024-11-22 03:39:15 +01:00
WIP
This commit is contained in:
parent
60a0679699
commit
cda1a77ec8
@ -1,6 +1,7 @@
|
||||
FROM wiiuenv/devkitppc:20211229
|
||||
FROM wiiuenv/devkitppc:20220724
|
||||
|
||||
COPY --from=wiiuenv/wiiupluginsystem:20220123 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libiosuhax:20220129 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiupluginsystem:20220724 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libkernel:20220724 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libmappedmemory:20220724 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
6
Makefile
6
Makefile
@ -39,10 +39,10 @@ CXXFLAGS := $(CFLAGS)
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld -T$(WUMS_ROOT)/share/libkernel.ld $(WUPSSPECS)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
|
||||
LIBS := -lwups -lwut -lkernel -lmappedmemory
|
||||
|
||||
@ -103,7 +103,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
121
src/debugger.cpp
121
src/debugger.cpp
@ -9,17 +9,14 @@
|
||||
#include <coreinit/exception.h>
|
||||
#include <coreinit/interrupts.h>
|
||||
#include <coreinit/memory.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
#include <coreinit/scheduler.h>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <gx2/context.h>
|
||||
#include <malloc.h>
|
||||
#include <sysapp/switch.h>
|
||||
#include <vpad/input.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
#include <vpad/input.h>
|
||||
|
||||
Debugger *debugger;
|
||||
bool initDebugState = false;
|
||||
@ -604,10 +601,11 @@ void Debugger::handleCrash(ExceptionState *state) {
|
||||
|
||||
void Debugger::handleFatalCrash(OSContext *context, ExceptionState::Type type) {
|
||||
const char *name;
|
||||
if (type == ExceptionState::DSI) name = "A DSI";
|
||||
else if (type == ExceptionState::ISI)
|
||||
if (type == ExceptionState::DSI) {
|
||||
name = "A DSI";
|
||||
} else if (type == ExceptionState::ISI) {
|
||||
name = "An ISI";
|
||||
else {
|
||||
} else {
|
||||
name = "A program";
|
||||
}
|
||||
DumpContext(context, name);
|
||||
@ -638,7 +636,7 @@ void Debugger::exceptionHandler(OSContext *context, ExceptionState::Type type) {
|
||||
}
|
||||
|
||||
BOOL Debugger::dsiHandler(OSContext *context) {
|
||||
OSContext *info = new OSContext();
|
||||
auto *info = new OSContext();
|
||||
memcpy(info, context, sizeof(OSContext));
|
||||
context->srr0 = (uint32_t) exceptionHandler;
|
||||
context->gpr[3] = (uint32_t) info;
|
||||
@ -673,48 +671,26 @@ void Debugger::cleanup() {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static const char **commandNames = (const char *[]){
|
||||
"COMMAND_CLOSE",
|
||||
"COMMAND_READ",
|
||||
"COMMAND_WRITE",
|
||||
"COMMAND_WRITE_CODE",
|
||||
"COMMAND_GET_MODULE_NAME",
|
||||
"COMMAND_GET_MODULE_LIST",
|
||||
"COMMAND_GET_THREAD_LIST",
|
||||
"COMMAND_GET_STACK_TRACE",
|
||||
"COMMAND_TOGGLE_BREAKPOINT",
|
||||
"COMMAND_POKE_REGISTERS",
|
||||
"COMMAND_RECEIVE_MESSAGES",
|
||||
"COMMAND_SEND_MESSAGE",
|
||||
"COMMAND_DISASM"};
|
||||
|
||||
|
||||
#define LOG_DISASSEMBLY_SIZE (4096)
|
||||
|
||||
static char
|
||||
sDisassemblyBuffer[LOG_DISASSEMBLY_SIZE];
|
||||
static char sDisassemblyBuffer[LOG_DISASSEMBLY_SIZE];
|
||||
|
||||
static uint32_t
|
||||
sDisassemblyLength = 0;
|
||||
static uint32_t sDisassemblyLength = 0;
|
||||
|
||||
|
||||
static void
|
||||
disassemblyPrintCallback(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
sDisassemblyLength += vsprintf(sDisassemblyBuffer + sDisassemblyLength,
|
||||
fmt, args);
|
||||
sDisassemblyLength += vsprintf(sDisassemblyBuffer + sDisassemblyLength, fmt, args);
|
||||
sDisassemblyBuffer[sDisassemblyLength] = 0;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void eraseAllSubStr(std::string & mainStr, const std::string & toErase)
|
||||
{
|
||||
void eraseAllSubStr(std::string &mainStr, const std::string &toErase) {
|
||||
size_t pos = std::string::npos;
|
||||
// Search for the substring in string in a loop untill nothing is found
|
||||
while ((pos = mainStr.find(toErase) )!= std::string::npos)
|
||||
{
|
||||
// Search for the substring in string in a loop until nothing is found
|
||||
while ((pos = mainStr.find(toErase)) != std::string::npos) {
|
||||
// If found then erase it from string
|
||||
mainStr.erase(pos, toErase.length());
|
||||
}
|
||||
@ -726,11 +702,10 @@ void eraseAllSubStr(std::string & mainStr, const std::string & toErase)
|
||||
void Debugger::mainLoop(Client *client) {
|
||||
while (!stopRunning) {
|
||||
uint8_t cmd;
|
||||
if (!client->recvall(&cmd, 1)) return;
|
||||
|
||||
if (cmd <= 12 && cmd != 10) {
|
||||
DEBUG_FUNCTION_LINE("Recieved command %s %d", commandNames[cmd], cmd);
|
||||
if (!client->recvall(&cmd, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == COMMAND_CLOSE) {
|
||||
return;
|
||||
} else if (cmd == COMMAND_READ) {
|
||||
@ -755,36 +730,25 @@ void Debugger::mainLoop(Client *client) {
|
||||
|
||||
auto addrAsPtr = (uint32_t *) (addr & 0xfffffffc);
|
||||
|
||||
|
||||
|
||||
|
||||
DisassemblePPCRange(reinterpret_cast<void *>(addr + 0x20), reinterpret_cast<void *>(addr + length), reinterpret_cast<DisassemblyPrintFn>(__os_printf),OSGetSymbolName,
|
||||
static_cast<DisassemblePPCFlags>(0x121));
|
||||
|
||||
|
||||
for (int i = 0; i < length / 4; i++) {
|
||||
DisassemblePPCOpcode(&addrAsPtr[i],
|
||||
buffer,
|
||||
0x40,
|
||||
OSGetSymbolName,
|
||||
static_cast<DisassemblePPCFlags>(0x121));
|
||||
if (OSIsAddressValid(reinterpret_cast<uint32_t>(&addrAsPtr[i]))) {
|
||||
DisassemblePPCOpcode(&addrAsPtr[i], buffer, 0x40, OSGetSymbolName, static_cast<DisassemblePPCFlags>(0x121));
|
||||
disassemblyPrintCallback("0x%08x 0x%08x %s\n", &addrAsPtr[i], addrAsPtr[i], buffer);
|
||||
} else {
|
||||
disassemblyPrintCallback("0x%08x ?????????? ???\n", &addrAsPtr[i]);
|
||||
}
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
std::string tmpString(sDisassemblyBuffer);
|
||||
eraseAllSubStr(tmpString, "(null)");
|
||||
|
||||
std::string shit(sDisassemblyBuffer);
|
||||
eraseAllSubStr(shit, "(null)");
|
||||
|
||||
|
||||
DEBUG_FUNCTION_LINE("done");
|
||||
|
||||
auto length_ = shit.length() + 1;
|
||||
auto length_ = tmpString.length() + 1;
|
||||
if (!client->sendall(&length_, 4)) {
|
||||
sDisassemblyLength = 0;
|
||||
return;
|
||||
}
|
||||
if (!client->sendall(shit.c_str(), length_)) {
|
||||
if (!client->sendall(tmpString.c_str(), length_)) {
|
||||
sDisassemblyLength = 0;
|
||||
return;
|
||||
}
|
||||
@ -817,28 +781,36 @@ void Debugger::mainLoop(Client *client) {
|
||||
if (!client->sendall(&length, 4)) return;
|
||||
if (!client->sendall(name, length)) return;
|
||||
} else if (cmd == COMMAND_GET_MODULE_LIST) {
|
||||
|
||||
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
||||
if (num_rpls == 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get OSDynLoad_GetNumberOfRPLs");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<OSDynLoad_NotifyData> rpls;
|
||||
rpls.resize(num_rpls);
|
||||
|
||||
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
||||
if (!ret) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get OSDynLoad_GetRPLInfo");
|
||||
continue;
|
||||
}
|
||||
auto BUFFER_SIZE = 0x1000; //This should be enough
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
char buffer[0x1000]; //This should be enough
|
||||
uint32_t offset = 0;
|
||||
|
||||
|
||||
for (auto &info : rpls) {
|
||||
uint32_t namelen = strlen(info.name);
|
||||
if (offset + 0x18 + namelen > 0x1000) {
|
||||
uint32_t namelen = 0;
|
||||
if (info.name != nullptr) {
|
||||
namelen = strlen(info.name);
|
||||
}
|
||||
|
||||
if (offset + 0x18 + namelen > BUFFER_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto *infobuf = (uint32_t *) (buffer + offset);
|
||||
infobuf[0] = info.textAddr;
|
||||
infobuf[1] = info.textSize;
|
||||
@ -846,11 +818,11 @@ void Debugger::mainLoop(Client *client) {
|
||||
infobuf[3] = info.dataSize;
|
||||
infobuf[4] = (uint32_t) 0; // TODO: missing
|
||||
infobuf[5] = namelen;
|
||||
if (namelen > 0) {
|
||||
memcpy(&infobuf[6], info.name, namelen);
|
||||
offset += 0x18 + strlen(info.name);
|
||||
}
|
||||
|
||||
//OSUnlockMutex(OSDynLoad_gLoaderLock);
|
||||
}
|
||||
|
||||
if (!client->sendall(&offset, 4)) return;
|
||||
if (!client->sendall(buffer, offset)) return;
|
||||
@ -858,19 +830,20 @@ void Debugger::mainLoop(Client *client) {
|
||||
int state = OSDisableInterrupts();
|
||||
__OSLockScheduler(this);
|
||||
|
||||
char buffer[0x1000]; //This should be enough
|
||||
auto BUFFER_SIZE = 0x1000; //This should be enough
|
||||
|
||||
char buffer[BUFFER_SIZE]; //This should be enough
|
||||
uint32_t offset = 0;
|
||||
OSThread *current = ThreadList;
|
||||
while (current) {
|
||||
const char *name = OSGetThreadName(current);
|
||||
OSReport("name %s", name);
|
||||
|
||||
uint32_t namelen = 0;
|
||||
if (name) {
|
||||
namelen = strlen(name);
|
||||
}
|
||||
|
||||
if (offset + 0x1C + namelen > 0x1000) {
|
||||
if (offset + 0x1C + namelen > BUFFER_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -978,7 +951,7 @@ void Debugger::mainLoop(Client *client) {
|
||||
}
|
||||
exceptions.unlock();
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Recieved unknown command %d", cmd);
|
||||
DEBUG_FUNCTION_LINE_ERR("Recieved unknown command %d", cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1027,7 +1000,7 @@ void Debugger::start() {
|
||||
serverStack = (char *) memalign(0x20, STACK_SIZE);
|
||||
|
||||
OSCreateThread(
|
||||
serverThread, threadEntry, 0, 0,
|
||||
serverThread, threadEntry, 0, nullptr,
|
||||
serverStack + STACK_SIZE, STACK_SIZE,
|
||||
0, OS_THREAD_ATTRIB_AFFINITY_CPU2 | OS_THREAD_ATTRIB_DETACHED);
|
||||
OSSetThreadName(serverThread, "Debug Server");
|
||||
|
@ -222,7 +222,7 @@ public:
|
||||
~Debugger();
|
||||
|
||||
private:
|
||||
enum Command {
|
||||
typedef enum Command {
|
||||
COMMAND_CLOSE,
|
||||
COMMAND_READ,
|
||||
COMMAND_WRITE,
|
||||
@ -236,7 +236,7 @@ private:
|
||||
COMMAND_RECEIVE_MESSAGES,
|
||||
COMMAND_SEND_MESSAGE,
|
||||
COMMAND_DISASM
|
||||
};
|
||||
} Command;
|
||||
|
||||
static int threadEntry(int argc, const char **argv);
|
||||
static BOOL dsiHandler(OSContext *context);
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
#include <cstdint>
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
void KernelWrite(uint32_t addr, const void *data, uint32_t length) {
|
||||
|
41
src/logger.h
41
src/logger.h
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
@ -7,31 +8,53 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG_APP_TYPE "P"
|
||||
#define LOG_APP_NAME "debugger_plugin"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
|
||||
|
||||
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
|
||||
|
||||
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
|
||||
do { \
|
||||
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
|
||||
#else
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
|
||||
#endif
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||
|
||||
#endif
|
||||
|
||||
void initLogging();
|
||||
|
18
src/main.cpp
18
src/main.cpp
@ -21,15 +21,15 @@ WUPS_USE_WUT_DEVOPTAB();
|
||||
/* https://github.com/QuarkTheAwesome/CafeBinPatch/blob/main/src/runtime-patcher.cpp#L58 */
|
||||
bool PatchInstruction(void *instr, uint32_t original, uint32_t replacement) {
|
||||
uint32_t current = *(uint32_t *) instr;
|
||||
if (current != original) return current == replacement;
|
||||
if (current != original) {
|
||||
return current == replacement;
|
||||
}
|
||||
|
||||
KernelCopyData(OSEffectiveToPhysical((uint32_t) instr), OSEffectiveToPhysical((uint32_t) &replacement), sizeof(replacement));
|
||||
//Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead
|
||||
DCFlushRange(instr, 4);
|
||||
ICInvalidateRange(instr, 4);
|
||||
|
||||
current = *(uint32_t *) instr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -55,20 +55,20 @@ INITIALIZE_PLUGIN() {
|
||||
|
||||
ON_APPLICATION_START() {
|
||||
initLogging();
|
||||
|
||||
DEBUG_FUNCTION_LINE("Hello from Debugger plugin");
|
||||
pThreadList = (OSThread **) 0x100567F8; // 100567f8
|
||||
debugger = new Debugger();
|
||||
DCFlushRange(&debugger, 4);
|
||||
DCFlushRange(debugger, sizeof(Debugger));
|
||||
DEBUG_FUNCTION_LINE("Created Debugger");
|
||||
OSMemoryBarrier();
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Created Debugger");
|
||||
debugger->start();
|
||||
DEBUG_FUNCTION_LINE("Started Debugger thread");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Started Debugger thread");
|
||||
}
|
||||
|
||||
ON_APPLICATION_REQUESTS_EXIT() {
|
||||
DEBUG_FUNCTION_LINE("Deleting Debugger thread");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Deleting Debugger thread");
|
||||
delete debugger;
|
||||
DEBUG_FUNCTION_LINE("Deleted Debugger thread");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Deleted Debugger thread");
|
||||
deinitLogging();
|
||||
}
|
||||
ON_APPLICATION_ENDS() {
|
||||
|
42
src/menu.cpp
42
src/menu.cpp
@ -1,42 +0,0 @@
|
||||
|
||||
#include "menu.h"
|
||||
#include "color.h"
|
||||
#include "input.h"
|
||||
#include <vpad/input.h>
|
||||
|
||||
Menu::Menu(Screen *screen) : screen(screen) {
|
||||
currentOption = LaunchDisk;
|
||||
message = nullptr;
|
||||
}
|
||||
|
||||
Menu::Option Menu::show() {
|
||||
while (true) {
|
||||
redraw();
|
||||
uint32_t buttons = WaitInput(VPAD_BUTTON_A | VPAD_BUTTON_DOWN | VPAD_BUTTON_UP);
|
||||
if (buttons & VPAD_BUTTON_A) return (Option) currentOption;
|
||||
else if (buttons & VPAD_BUTTON_DOWN) {
|
||||
if (currentOption < 2) currentOption++;
|
||||
} else if (buttons & VPAD_BUTTON_UP) {
|
||||
if (currentOption > 0) currentOption--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::setMessage(const char *message) {
|
||||
this->message = message;
|
||||
redraw();
|
||||
}
|
||||
|
||||
void Menu::redraw() {
|
||||
screen->clear(COLOR_BLUE);
|
||||
Screen::drawText(5, 5, "Wii U Debugger");
|
||||
Screen::drawText(5, 7, "Choose an option:");
|
||||
Screen::drawText(8, 9, "Install and launch disc");
|
||||
Screen::drawText(8, 10, "Install and return to system menu");
|
||||
Screen::drawText(8, 11, "Exit without installing");
|
||||
Screen::drawText(5, 9 + currentOption, ">");
|
||||
if (message) {
|
||||
Screen::drawText(5, 13, message);
|
||||
}
|
||||
Screen::flip();
|
||||
}
|
22
src/menu.h
22
src/menu.h
@ -1,22 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
class Menu {
|
||||
public:
|
||||
enum Option { LaunchDisk,
|
||||
ReturnToMenu,
|
||||
Exit };
|
||||
|
||||
Menu(Screen *screen);
|
||||
Option show();
|
||||
void setMessage(const char *message);
|
||||
void redraw();
|
||||
|
||||
private:
|
||||
Screen *screen;
|
||||
int currentOption;
|
||||
|
||||
const char *message;
|
||||
};
|
@ -19,9 +19,11 @@ void Screen::init() {
|
||||
uint32_t bufferSize0 = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t bufferSize1 = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
screenBuffer = MEMAllocFromMappedMemoryForGX2Ex(bufferSize0 + bufferSize1, 0x100);
|
||||
|
||||
if (screenBuffer == nullptr) {
|
||||
OSFatal("Failed to allocate screenbuffer");
|
||||
}
|
||||
memset(screenBuffer, 0, bufferSize0 + bufferSize1);
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, (char *) screenBuffer + bufferSize0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user