Merge branch 'master' into medusa

This commit is contained in:
Vicki Pfau 2017-07-16 14:43:22 -07:00
commit 45169bc0f2
24 changed files with 506 additions and 25 deletions

View File

@ -8,6 +8,8 @@ Misc:
- DS GX: Clean up and unify texture mapping - DS GX: Clean up and unify texture mapping
0.7.0: (Future) 0.7.0: (Future)
Features:
- ELF support
Bugfixes: Bugfixes:
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
Misc: Misc:
@ -15,7 +17,7 @@ Misc:
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
- All: Make FIXED_ROM_BUFFER an option instead of 3DS-only - All: Make FIXED_ROM_BUFFER an option instead of 3DS-only
0.6.0: (Future) 0.6.0: (2017-07-16)
Features: Features:
- Library view - Library view
- Sprite viewer - Sprite viewer
@ -190,6 +192,8 @@ Bugfixes:
- Core: Fix rewinding getting out of sync (fixes mgba.io/i/791) - Core: Fix rewinding getting out of sync (fixes mgba.io/i/791)
- Qt: Fix GL-less build - Qt: Fix GL-less build
- Qt: Fix Software renderer not handling alpha bits properly - Qt: Fix Software renderer not handling alpha bits properly
- Qt: Fix screen background improperly stretching
- SDL: Fix cheats not loading
Misc: Misc:
- GB Serialize: Add MBC state serialization - GB Serialize: Add MBC state serialization
- GBA Memory: Call crash callbacks regardless of if hard crash is enabled - GBA Memory: Call crash callbacks regardless of if hard crash is enabled

View File

@ -16,6 +16,7 @@ set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support")
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support") set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support") set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support")
set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support") set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support")
set(USE_ELF ON CACHE BOOL "Whether or not to enable ELF support")
set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core") set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core") set(M_CORE_GB ON CACHE BOOL "Build Game Boy core")
set(M_CORE_DS ON CACHE BOOL "Build DS core") set(M_CORE_DS ON CACHE BOOL "Build DS core")
@ -402,6 +403,7 @@ find_feature(USE_MAGICK "MagickWand")
find_feature(USE_EPOXY "epoxy") find_feature(USE_EPOXY "epoxy")
find_feature(USE_CMOCKA "cmocka") find_feature(USE_CMOCKA "cmocka")
find_feature(USE_SQLITE3 "sqlite3") find_feature(USE_SQLITE3 "sqlite3")
find_feature(USE_ELF "libelf")
find_feature(ENABLE_PYTHON "PythonLibs") find_feature(ENABLE_PYTHON "PythonLibs")
# Features # Features
@ -620,6 +622,17 @@ if(USE_SQLITE3)
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/sqlite3/no-intro.c") list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/sqlite3/no-intro.c")
endif() endif()
if(USE_ELF)
list(APPEND FEATURES ELF)
include_directories(AFTER ${LIBELF_INCLUDE_DIRS})
find_file(ELF_REPL_H elf_repl.h PATHS ${LIBELF_INCLUDE_DIRS})
if (ELF_REPL_H)
add_definitions(-DUSE_ELF_REPL)
endif()
list(APPEND DEPENDENCY_LIB ${LIBELF_LIBRARIES})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libelfg0")
endif()
if(ENABLE_SCRIPTING) if(ENABLE_SCRIPTING)
list(APPEND ENABLES SCRIPTING) list(APPEND ENABLES SCRIPTING)
@ -967,6 +980,7 @@ if(NOT QUIET)
message(STATUS " ZIP support: ${SUMMARY_ZIP}") message(STATUS " ZIP support: ${SUMMARY_ZIP}")
message(STATUS " 7-Zip support: ${USE_LZMA}") message(STATUS " 7-Zip support: ${USE_LZMA}")
message(STATUS " SQLite3 game database: ${USE_SQLITE3}") message(STATUS " SQLite3 game database: ${USE_SQLITE3}")
message(STATUS " ELF loading support: ${USE_ELF}")
message(STATUS " OpenGL support: ${SUMMARY_GL}") message(STATUS " OpenGL support: ${SUMMARY_GL}")
message(STATUS "Frontends:") message(STATUS "Frontends:")
message(STATUS " Qt: ${BUILD_QT}") message(STATUS " Qt: ${BUILD_QT}")

View File

@ -160,6 +160,7 @@ medusa has no hard dependencies, however, the following optional dependencies ar
- libzip or zlib: for loading ROMs stored in zip files. - libzip or zlib: for loading ROMs stored in zip files.
- ImageMagick: for GIF recording. - ImageMagick: for GIF recording.
- SQLite3: for game databases. - SQLite3: for game databases.
- libelf: for ELF loading.
SQLite3, libpng, and zlib are included with the emulator, so they do not need to be externally compiled first. SQLite3, libpng, and zlib are included with the emulator, so they do not need to be externally compiled first.

View File

@ -0,0 +1,51 @@
/* Copyright (c) 2013-2017 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ELF_READ_H
#define ELF_READ_H
#include <mgba-util/common.h>
CXX_GUARD_START
#ifdef USE_ELF
#include <libelf.h>
#if USE_ELF_REPL
#include <elf_repl.h>
#else
#include <elf.h>
#endif
#include <mgba-util/vector.h>
struct ELF;
struct VFile;
DECLARE_VECTOR(ELFProgramHeaders, Elf32_Phdr);
DECLARE_VECTOR(ELFSectionHeaders, Elf32_Shdr);
struct ELF* ELFOpen(struct VFile*);
void ELFClose(struct ELF*);
void* ELFBytes(struct ELF*, size_t* size);
uint16_t ELFMachine(struct ELF*);
uint32_t ELFEntry(struct ELF*);
void ELFGetProgramHeaders(struct ELF*, struct ELFProgramHeaders*);
size_t ELFFindSection(struct ELF*, const char* name);
void ELFGetSectionHeaders(struct ELF*, struct ELFSectionHeaders*);
Elf32_Shdr* ELFGetSectionHeader(struct ELF*, size_t index);
const char* ELFGetString(struct ELF*, size_t section, size_t string);
#endif
CXX_GUARD_END
#endif

View File

@ -196,6 +196,14 @@ void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config
void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc); void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc);
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size);
#ifdef USE_ELF
struct ELF;
bool mCoreLoadELF(struct mCore* core, struct ELF* elf);
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF*);
#endif
CXX_GUARD_END CXX_GUARD_END
#endif #endif

View File

@ -24,6 +24,7 @@ struct mScriptEngine {
bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf); bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf); bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
void (*run)(struct mScriptEngine*); void (*run)(struct mScriptEngine*);
bool (*lookupSymbol)(struct mScriptEngine*, const char* name, int32_t* out);
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
@ -44,6 +45,8 @@ void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReas
void mScriptBridgeRun(struct mScriptBridge*); void mScriptBridgeRun(struct mScriptBridge*);
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name); bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
CXX_GUARD_END CXX_GUARD_END
#endif #endif

View File

@ -91,6 +91,7 @@ struct mDebugger {
struct mCPUComponent d; struct mCPUComponent d;
struct mDebuggerPlatform* platform; struct mDebuggerPlatform* platform;
enum mDebuggerState state; enum mDebuggerState state;
enum mDebuggerType type;
struct mCore* core; struct mCore* core;
struct mScriptBridge* bridge; struct mScriptBridge* bridge;

View File

@ -168,6 +168,7 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf);
void GBAApplyPatch(struct GBA* gba, struct Patch* patch); void GBAApplyPatch(struct GBA* gba, struct Patch* patch);
bool GBALoadMB(struct GBA* gba, struct VFile* vf); bool GBALoadMB(struct GBA* gba, struct VFile* vf);
bool GBALoadNull(struct GBA* gba);
bool GBAIsROM(struct VFile* vf); bool GBAIsROM(struct VFile* vf);
bool GBAIsMB(struct VFile* vf); bool GBAIsMB(struct VFile* vf);

View File

@ -8,6 +8,11 @@
#include <mgba/core/log.h> #include <mgba/core/log.h>
#include <mgba/core/serialize.h> #include <mgba/core/serialize.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
#include <mgba/internal/debugger/symbols.h>
#ifdef USE_ELF
#include <mgba-util/elf-read.h>
#endif
#ifdef M_CORE_GB #ifdef M_CORE_GB
#include <mgba/gb/core.h> #include <mgba/gb/core.h>
@ -280,3 +285,67 @@ void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
core->rtc.custom = rtc; core->rtc.custom = rtc;
core->rtc.override = RTC_CUSTOM_START; core->rtc.override = RTC_CUSTOM_START;
} }
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size) {
const struct mCoreMemoryBlock* blocks;
size_t nBlocks = core->listMemoryBlocks(core, &blocks);
size_t i;
for (i = 0; i < nBlocks; ++i) {
if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) {
continue;
}
if (start < blocks[i].start) {
continue;
}
if (start >= blocks[i].start + blocks[i].size) {
continue;
}
uint8_t* out = core->getMemoryBlock(core, blocks[i].id, size);
out += start - blocks[i].start;
*size -= start - blocks[i].start;
return out;
}
return NULL;
}
#ifdef USE_ELF
bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
struct ELFProgramHeaders ph;
ELFProgramHeadersInit(&ph, 0);
ELFGetProgramHeaders(elf, &ph);
size_t i;
for (i = 0; i < ELFProgramHeadersSize(&ph); ++i) {
size_t bsize, esize;
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
void* block = mCoreGetMemoryBlock(core, phdr->p_paddr, &bsize);
char* bytes = ELFBytes(elf, &esize);
if (block && bsize >= phdr->p_filesz && esize >= phdr->p_filesz + phdr->p_offset) {
memcpy(block, &bytes[phdr->p_offset], phdr->p_filesz);
} else {
return false;
}
}
return true;
}
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF* elf) {
size_t symIndex = ELFFindSection(elf, ".symtab");
size_t names = ELFFindSection(elf, ".strtab");
Elf32_Shdr* symHeader = ELFGetSectionHeader(elf, symIndex);
char* bytes = ELFBytes(elf, NULL);
Elf32_Sym* syms = (Elf32_Sym*) &bytes[symHeader->sh_offset];
size_t i;
for (i = 0; i * sizeof(*syms) < symHeader->sh_size; ++i) {
if (!syms[i].st_name || ELF32_ST_TYPE(syms[i].st_info) == STT_FILE) {
continue;
}
const char* name = ELFGetString(elf, names, syms[i].st_name);
if (name[0] == '$') {
continue;
}
mDebuggerSymbolAdd(symbols, name, syms[i].st_value, -1);
}
}
#endif

View File

@ -19,6 +19,12 @@ struct mScriptInfo {
bool success; bool success;
}; };
struct mScriptSymbol {
const char* name;
int32_t* out;
bool success;
};
static void _seDeinit(void* value) { static void _seDeinit(void* value) {
struct mScriptEngine* se = value; struct mScriptEngine* se = value;
se->deinit(se); se->deinit(se);
@ -33,6 +39,15 @@ static void _seTryLoad(const char* key, void* value, void* user) {
} }
} }
static void _seLookupSymbol(const char* key, void* value, void* user) {
UNUSED(key);
struct mScriptEngine* se = value;
struct mScriptSymbol* si = user;
if (!si->success) {
si->success = se->lookupSymbol(se, si->name, si->out);
}
}
static void _seRun(const char* key, void* value, void* user) { static void _seRun(const char* key, void* value, void* user) {
UNUSED(key); UNUSED(key);
UNUSED(user); UNUSED(user);
@ -111,3 +126,13 @@ bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
vf->close(vf); vf->close(vf);
return info.success; return info.success;
} }
bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) {
struct mScriptSymbol info = {
.name = name,
.out = out,
.success = false
};
HashTableEnumerate(&sb->engines, _seLookupSymbol, &info);
return info.success;
}

View File

@ -551,6 +551,11 @@ static void _lookupIdentifier(struct mDebugger* debugger, const char* name, stru
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
if (cliDebugger->system) { if (cliDebugger->system) {
uint32_t value; uint32_t value;
#ifdef ENABLE_SCRIPTING
if (debugger->bridge && mScriptBridgeLookupSymbol(debugger->bridge, name, &dv->intValue)) {
return;
}
#endif
if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, &dv->intValue, &dv->segmentValue)) { if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, &dv->intValue, &dv->segmentValue)) {
return; return;
} }
@ -832,6 +837,7 @@ void CLIDebuggerCreate(struct CLIDebugger* debugger) {
debugger->d.custom = _cliDebuggerCustom; debugger->d.custom = _cliDebuggerCustom;
debugger->d.paused = _commandLine; debugger->d.paused = _commandLine;
debugger->d.entered = _reportEntry; debugger->d.entered = _reportEntry;
debugger->d.type = DEBUGGER_CLI;
debugger->system = NULL; debugger->system = NULL;
debugger->backend = NULL; debugger->backend = NULL;

View File

@ -658,6 +658,7 @@ void GDBStubCreate(struct GDBStub* stub) {
stub->d.paused = _gdbStubWait; stub->d.paused = _gdbStubWait;
stub->d.entered = _gdbStubEntered; stub->d.entered = _gdbStubEntered;
stub->d.custom = _gdbStubPoll; stub->d.custom = _gdbStubPoll;
stub->d.type = DEBUGGER_GDB;
stub->untilPoll = GDB_STUB_INTERVAL; stub->untilPoll = GDB_STUB_INTERVAL;
stub->lineAck = GDB_ACK_PENDING; stub->lineAck = GDB_ACK_PENDING;
stub->shouldBlock = false; stub->shouldBlock = false;

View File

@ -8,6 +8,7 @@
#include <mgba/core/core.h> #include <mgba/core/core.h>
#include <mgba/core/log.h> #include <mgba/core/log.h>
#include <mgba/internal/arm/debugger/debugger.h> #include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/internal/debugger/symbols.h>
#include <mgba/internal/gba/cheats.h> #include <mgba/internal/gba/cheats.h>
#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h> #include <mgba/internal/gba/io.h>
@ -20,6 +21,9 @@
#include <mgba/internal/gba/renderers/video-software.h> #include <mgba/internal/gba/renderers/video-software.h>
#include <mgba/internal/gba/savedata.h> #include <mgba/internal/gba/savedata.h>
#include <mgba/internal/gba/serialize.h> #include <mgba/internal/gba/serialize.h>
#ifdef USE_ELF
#include <mgba-util/elf-read.h>
#endif
#include <mgba-util/memory.h> #include <mgba-util/memory.h>
#include <mgba-util/patch.h> #include <mgba-util/patch.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
@ -318,6 +322,15 @@ static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
} }
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) { static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
GBALoadNull(core->board);
bool success = mCoreLoadELF(core, elf);
ELFClose(elf);
return success;
}
#endif
if (GBAIsMB(vf)) { if (GBAIsMB(vf)) {
return GBALoadMB(core->board, vf); return GBALoadMB(core->board, vf);
} }
@ -718,7 +731,27 @@ static void _GBACoreDetachDebugger(struct mCore* core) {
} }
static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) { static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
// TODO #ifdef USE_ELF
bool closeAfter = false;
core->symbolTable = mDebuggerSymbolTableCreate();
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
if (!vf) {
closeAfter = true;
vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".elf", O_RDONLY);
}
#endif
if (!vf) {
return;
}
struct ELF* elf = ELFOpen(vf);
if (elf) {
mCoreLoadELFSymbols(core->symbolTable, elf);
ELFClose(elf);
}
if (closeAfter) {
vf->close(vf);
}
#endif
} }
#endif #endif

View File

@ -21,6 +21,10 @@
#include <mgba-util/memory.h> #include <mgba-util/memory.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
#ifdef USE_ELF
#include <mgba-util/elf-read.h>
#endif
mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba"); mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba");
mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug"); mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");
@ -203,6 +207,10 @@ void GBAReset(struct ARMCore* cpu) {
gba->debug = false; gba->debug = false;
memset(gba->debugString, 0, sizeof(gba->debugString)); memset(gba->debugString, 0, sizeof(gba->debugString));
if (!gba->romVf) {
GBASkipBIOS(gba);
}
} }
void GBASkipBIOS(struct GBA* gba) { void GBASkipBIOS(struct GBA* gba) {
@ -288,6 +296,25 @@ void GBADetachDebugger(struct GBA* gba) {
} }
#endif #endif
bool GBALoadNull(struct GBA* gba) {
GBAUnloadROM(gba);
gba->romVf = NULL;
gba->pristineRomSize = 0;
gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
#ifndef FIXED_ROM_BUFFER
gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
#else
gba->memory.rom = romBuffer;
#endif
gba->isPristine = false;
gba->yankedRomSize = 0;
gba->memory.romSize = SIZE_CART0;
gba->memory.romMask = SIZE_CART0 - 1;
gba->memory.mirroring = false;
gba->romCrc32 = 0;
return true;
}
bool GBALoadMB(struct GBA* gba, struct VFile* vf) { bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
GBAUnloadROM(gba); GBAUnloadROM(gba);
gba->romVf = vf; gba->romVf = vf;
@ -478,6 +505,17 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
} }
bool GBAIsROM(struct VFile* vf) { bool GBAIsROM(struct VFile* vf) {
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
uint32_t entry = ELFEntry(elf);
bool isGBA = true;
isGBA = isGBA && ELFMachine(elf) == EM_ARM;
isGBA = isGBA && (entry == BASE_CART0 || entry == BASE_WORKING_RAM);
ELFClose(elf);
return isGBA;
}
#endif
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) { if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
return false; return false;
} }
@ -495,6 +533,14 @@ bool GBAIsMB(struct VFile* vf) {
if (!GBAIsROM(vf)) { if (!GBAIsROM(vf)) {
return false; return false;
} }
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
bool isMB = ELFEntry(elf) == BASE_WORKING_RAM;
ELFClose(elf);
return isMB;
}
#endif
if (vf->size(vf) > SIZE_WORKING_RAM) { if (vf->size(vf) > SIZE_WORKING_RAM) {
return false; return false;
} }

View File

@ -80,6 +80,8 @@ void GBAMemoryInit(struct GBA* gba) {
gba->memory.biosPrefetch = 0; gba->memory.biosPrefetch = 0;
gba->memory.mirroring = false; gba->memory.mirroring = false;
gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
GBADMAInit(gba); GBADMAInit(gba);
GBAVFameInit(&gba->memory.vfame); GBAVFameInit(&gba->memory.vfame);
} }
@ -107,9 +109,8 @@ void GBAMemoryReset(struct GBA* gba) {
} }
if (gba->memory.iwram) { if (gba->memory.iwram) {
mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM); memset(gba->memory.iwram, 0, SIZE_WORKING_IRAM);
} }
gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
memset(gba->memory.io, 0, sizeof(gba->memory.io)); memset(gba->memory.io, 0, sizeof(gba->memory.io));

View File

@ -58,4 +58,5 @@ void free(void*);
#endif #endif
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
#include <mgba/debugger/debugger.h> #include <mgba/debugger/debugger.h>
#include <mgba/internal/debugger/cli-debugger.h>
#endif #endif

View File

@ -28,6 +28,7 @@ ffi.set_source("mgba._pylib", """
#include <mgba/core/version.h> #include <mgba/core/version.h>
#include <mgba/debugger/debugger.h> #include <mgba/debugger/debugger.h>
#include <mgba/internal/arm/arm.h> #include <mgba/internal/arm/arm.h>
#include <mgba/internal/debugger/cli-debugger.h>
#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/input.h> #include <mgba/internal/gba/input.h>
#include <mgba/internal/gba/renderers/tile-cache.h> #include <mgba/internal/gba/renderers/tile-cache.h>
@ -70,17 +71,27 @@ for line in preprocessed.splitlines():
ffi.embedding_api('\n'.join(lines)) ffi.embedding_api('\n'.join(lines))
ffi.embedding_init_code(""" ffi.embedding_init_code("""
from mgba._pylib import ffi from mgba._pylib import ffi, lib
debugger = None symbols = {}
globalSyms = {
'symbols': symbols
}
pendingCode = [] pendingCode = []
@ffi.def_extern() @ffi.def_extern()
def mPythonSetDebugger(_debugger): def mPythonSetDebugger(debugger):
from mgba.debugger import NativeDebugger from mgba.debugger import NativeDebugger, CLIDebugger
global debugger oldDebugger = globalSyms.get('debugger')
if debugger and debugger._native == _debugger: if oldDebugger and oldDebugger._native == debugger:
return return
debugger = _debugger and NativeDebugger(_debugger) if oldDebugger and not debugger:
del globalSyms['debugger']
return
if debugger.type == lib.DEBUGGER_CLI:
debugger = CLIDebugger(debugger)
else:
debugger = NativeDebugger(debugger)
globalSyms['debugger'] = debugger
@ffi.def_extern() @ffi.def_extern()
def mPythonLoadScript(name, vf): def mPythonLoadScript(name, vf):
@ -99,18 +110,40 @@ ffi.embedding_init_code("""
def mPythonRunPending(): def mPythonRunPending():
global pendingCode global pendingCode
for code in pendingCode: for code in pendingCode:
exec(code) exec(code, globalSyms, {})
pendingCode = [] pendingCode = []
@ffi.def_extern() @ffi.def_extern()
def mPythonDebuggerEntered(reason, info): def mPythonDebuggerEntered(reason, info):
global debugger debugger = globalSyms['debugger']
if not debugger: if not debugger:
return return
if info == ffi.NULL: if info == ffi.NULL:
info = None info = None
for cb in debugger._cbs: for cb in debugger._cbs:
cb(reason, info) cb(reason, info)
@ffi.def_extern()
def mPythonLookupSymbol(name, outptr):
name = ffi.string(name).decode('utf-8')
if name not in symbols:
return False
sym = symbols[name]
val = None
try:
val = int(sym)
except:
try:
val = sym()
except:
pass
if val is None:
return False
try:
outptr[0] = ffi.cast('int32_t', val)
return True
except:
return False
""") """)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -21,6 +21,7 @@ static void mPythonScriptEngineDeinit(struct mScriptEngine*);
static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf); static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf);
static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf); static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf);
static void mPythonScriptEngineRun(struct mScriptEngine*); static void mPythonScriptEngineRun(struct mScriptEngine*);
static bool mPythonScriptEngineLookupSymbol(struct mScriptEngine*, const char* name, int32_t* out);
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
@ -39,6 +40,7 @@ struct mPythonScriptEngine* mPythonCreateScriptEngine(void) {
engine->d.isScript = mPythonScriptEngineIsScript; engine->d.isScript = mPythonScriptEngineIsScript;
engine->d.loadScript = mPythonScriptEngineLoadScript; engine->d.loadScript = mPythonScriptEngineLoadScript;
engine->d.run = mPythonScriptEngineRun; engine->d.run = mPythonScriptEngineRun;
engine->d.lookupSymbol = mPythonScriptEngineLookupSymbol;
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
engine->d.debuggerEntered = mPythonScriptDebuggerEntered; engine->d.debuggerEntered = mPythonScriptDebuggerEntered;
#endif #endif
@ -89,6 +91,11 @@ void mPythonScriptEngineRun(struct mScriptEngine* se) {
mPythonRunPending(); mPythonRunPending();
} }
bool mPythonScriptEngineLookupSymbol(struct mScriptEngine* se, const char* name, int32_t* out) {
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
return mPythonLookupSymbol(name, out);
}
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;

View File

@ -4,6 +4,7 @@ struct VFile;
extern bool mPythonLoadScript(const char*, struct VFile*); extern bool mPythonLoadScript(const char*, struct VFile*);
extern void mPythonRunPending(); extern void mPythonRunPending();
extern bool mPythonLookupSymbol(const char* name, int32_t* out);
#ifdef USE_DEBUGGERS #ifdef USE_DEBUGGERS
extern void mPythonSetDebugger(struct mDebugger*); extern void mPythonSetDebugger(struct mDebugger*);

View File

@ -5,6 +5,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib from ._pylib import ffi, lib
from .core import IRunner, ICoreOwner, Core from .core import IRunner, ICoreOwner, Core
import io
import sys
class DebuggerCoreOwner(ICoreOwner): class DebuggerCoreOwner(ICoreOwner):
def __init__(self, debugger): def __init__(self, debugger):
@ -78,3 +80,22 @@ class NativeDebugger(IRunner):
def addCallback(self, cb): def addCallback(self, cb):
self._cbs.append(cb) self._cbs.append(cb)
class CLIBackend(object):
def __init__(self, backend):
self.backend = backend
def write(self, string):
self.backend.printf(string)
class CLIDebugger(NativeDebugger):
def __init__(self, native):
super(CLIDebugger, self).__init__(native)
self._cli = ffi.cast("struct CLIDebugger*", native)
def printf(self, message, *args, **kwargs):
message = message.format(*args, **kwargs)
self._cli.backend.printf(ffi.new("char []", b"%s"), ffi.new("char []", message.encode('utf-8')))
def installPrint(self):
sys.stdout = CLIBackend(self)

View File

@ -155,7 +155,9 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
#endif #endif
m_screenWidget->setPixmap(m_logo); m_screenWidget->setPixmap(m_logo);
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height()); m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
m_screenWidget->setLockIntegerScaling(false); m_screenWidget->setLockIntegerScaling(false);
m_screenWidget->setLockAspectRatio(true);
setCentralWidget(m_screenWidget); setCentralWidget(m_screenWidget);
connect(m_controller, &GameController::gameStarted, this, &Window::gameStarted); connect(m_controller, &GameController::gameStarted, this, &Window::gameStarted);
@ -173,7 +175,6 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
QPixmap pixmap; QPixmap pixmap;
pixmap.convertFromImage(currentImage); pixmap.convertFromImage(currentImage);
m_screenWidget->setPixmap(pixmap); m_screenWidget->setPixmap(pixmap);
m_screenWidget->setLockAspectRatio(width, height);
}); });
connect(m_controller, &GameController::gamePaused, m_display, &Display::pauseDrawing); connect(m_controller, &GameController::gamePaused, m_display, &Display::pauseDrawing);
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
@ -803,7 +804,9 @@ void Window::gameStarted(mCoreThread* context, const QString& fname) {
context->core->desiredVideoDimensions(context->core, &width, &height); context->core->desiredVideoDimensions(context->core, &width, &height);
m_display->setMinimumSize(width, height); m_display->setMinimumSize(width, height);
m_screenWidget->setMinimumSize(m_display->minimumSize()); m_screenWidget->setMinimumSize(m_display->minimumSize());
m_screenWidget->setDimensions(width, height);
m_config->updateOption("lockIntegerScaling"); m_config->updateOption("lockIntegerScaling");
m_config->updateOption("lockAspectRatio");
if (m_savedScale > 0) { if (m_savedScale > 0) {
resizeFrame(QSize(width, height) * m_savedScale); resizeFrame(QSize(width, height) * m_savedScale);
} }
@ -867,7 +870,9 @@ void Window::gameStopped() {
updateTitle(); updateTitle();
detachWidget(m_display); detachWidget(m_display);
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height()); m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
m_screenWidget->setLockIntegerScaling(false); m_screenWidget->setLockIntegerScaling(false);
m_screenWidget->setLockAspectRatio(true);
m_screenWidget->setPixmap(m_logo); m_screenWidget->setPixmap(m_logo);
m_screenWidget->unsetCursor(); m_screenWidget->unsetCursor();
#ifdef M_CORE_GB #ifdef M_CORE_GB
@ -1341,6 +1346,9 @@ void Window::setupMenu(QMenuBar* menubar) {
lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu); lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu);
lockAspectRatio->connect([this](const QVariant& value) { lockAspectRatio->connect([this](const QVariant& value) {
m_display->lockAspectRatio(value.toBool()); m_display->lockAspectRatio(value.toBool());
if (m_controller->isLoaded()) {
m_screenWidget->setLockAspectRatio(value.toBool());
}
}, this); }, this);
m_config->updateOption("lockAspectRatio"); m_config->updateOption("lockAspectRatio");
@ -1670,14 +1678,13 @@ QSize WindowBackground::sizeHint() const {
return m_sizeHint; return m_sizeHint;
} }
void WindowBackground::setLockAspectRatio(int width, int height) {
m_centered = false;
m_aspectWidth = width;
m_aspectHeight = height;
}
void WindowBackground::setCenteredAspectRatio(int width, int height) { void WindowBackground::setCenteredAspectRatio(int width, int height) {
m_centered = true; m_centered = true;
m_lockAspectRatio = true;
setDimensions(width, height);
}
void WindowBackground::setDimensions(int width, int height) {
m_aspectWidth = width; m_aspectWidth = width;
m_aspectHeight = height; m_aspectHeight = height;
} }
@ -1686,6 +1693,11 @@ void WindowBackground::setLockIntegerScaling(bool lock) {
m_lockIntegerScaling = lock; m_lockIntegerScaling = lock;
} }
void WindowBackground::setLockAspectRatio(bool lock) {
m_centered = false;
m_lockAspectRatio = lock;
}
void WindowBackground::paintEvent(QPaintEvent*) { void WindowBackground::paintEvent(QPaintEvent*) {
const QPixmap* logo = pixmap(); const QPixmap* logo = pixmap();
if (!logo) { if (!logo) {
@ -1702,7 +1714,7 @@ void WindowBackground::paintEvent(QPaintEvent*) {
} else if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) { } else if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth); ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
} }
} else { } else if (m_lockAspectRatio) {
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) { if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight); ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) { } else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {

View File

@ -210,9 +210,10 @@ public:
void setSizeHint(const QSize& size); void setSizeHint(const QSize& size);
virtual QSize sizeHint() const override; virtual QSize sizeHint() const override;
void setLockAspectRatio(int width, int height); void setDimensions(int width, int height);
void setCenteredAspectRatio(int width, int height); void setCenteredAspectRatio(int width, int height);
void setLockIntegerScaling(bool lock); void setLockIntegerScaling(bool lock);
void setLockAspectRatio(bool lock);
protected: protected:
virtual void paintEvent(QPaintEvent*) override; virtual void paintEvent(QPaintEvent*) override;
@ -222,6 +223,7 @@ private:
bool m_centered; bool m_centered;
int m_aspectWidth; int m_aspectWidth;
int m_aspectHeight; int m_aspectHeight;
bool m_lockAspectRatio;
bool m_lockIntegerScaling; bool m_lockIntegerScaling;
}; };

View File

@ -21,6 +21,7 @@
#endif #endif
#endif #endif
#include <mgba/core/cheats.h>
#include <mgba/core/core.h> #include <mgba/core/core.h>
#include <mgba/core/config.h> #include <mgba/core/config.h>
#include <mgba/core/input.h> #include <mgba/core/input.h>
@ -104,6 +105,16 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
struct mCheatDevice* device = NULL;
if (args.cheatsFile && (device = renderer.core->cheatDevice(renderer.core))) {
struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY);
if (vf) {
mCheatDeviceClear(device);
mCheatParseFile(device, vf);
vf->close(vf);
}
}
mInputMapInit(&renderer.core->inputMap, renderer.core->inputInfo); mInputMapInit(&renderer.core->inputMap, renderer.core->inputInfo);
mCoreInitConfig(renderer.core, PORT); mCoreInitConfig(renderer.core, PORT);
applyArguments(&args, &subparser, &renderer.core->config); applyArguments(&args, &subparser, &renderer.core->config);
@ -148,6 +159,10 @@ int main(int argc, char** argv) {
mSDLDetachPlayer(&renderer.events, &renderer.player); mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&renderer.core->inputMap); mInputMapDeinit(&renderer.core->inputMap);
if (device) {
mCheatDeviceDestroy(device);
}
mSDLDeinit(&renderer); mSDLDeinit(&renderer);
freeArguments(&args); freeArguments(&args);
@ -184,10 +199,10 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
#endif #endif
mDebuggerAttach(debugger, renderer->core); mDebuggerAttach(debugger, renderer->core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
} #ifdef ENABLE_SCRIPTING
#ifdef ENABLE_SCRIPTING
mScriptBridgeSetDebugger(bridge, debugger); mScriptBridgeSetDebugger(bridge, debugger);
#endif #endif
}
#endif #endif
if (args->patch) { if (args->patch) {

125
src/util/elf-read.c Normal file
View File

@ -0,0 +1,125 @@
/* Copyright (c) 2013-2017 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba-util/elf-read.h>
#ifdef USE_ELF
#include <mgba-util/vfs.h>
DEFINE_VECTOR(ELFProgramHeaders, Elf32_Phdr);
DEFINE_VECTOR(ELFSectionHeaders, Elf32_Shdr);
static bool _elfInit = false;
struct ELF {
Elf* e;
struct VFile* vf;
size_t size;
char* memory;
};
struct ELF* ELFOpen(struct VFile* vf) {
if (!_elfInit) {
_elfInit = elf_version(EV_CURRENT) != EV_NONE;
if (!_elfInit) {
return NULL;
}
}
if (!vf) {
return NULL;
}
size_t size = vf->size(vf);
char* memory = vf->map(vf, size, MAP_READ);
if (!memory) {
return NULL;
}
Elf* e = elf_memory(memory, size);
if (!e || elf_kind(e) != ELF_K_ELF) {
elf_end(e);
vf->unmap(vf, memory, size);
return false;
}
struct ELF* elf = malloc(sizeof(*elf));
elf->e = e;
elf->vf = vf;
elf->size = size;
elf->memory = memory;
return elf;
}
void ELFClose(struct ELF* elf) {
elf_end(elf->e);
elf->vf->unmap(elf->vf, elf->memory, elf->size);
free(elf);
}
void* ELFBytes(struct ELF* elf, size_t* size) {
if (size) {
*size = elf->size;
}
return elf->memory;
}
uint16_t ELFMachine(struct ELF* elf) {
Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
if (!hdr) {
return 0;
}
return hdr->e_machine;
}
uint32_t ELFEntry(struct ELF* elf) {
Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
if (!hdr) {
return 0;
}
return hdr->e_entry;
}
void ELFGetProgramHeaders(struct ELF* elf, struct ELFProgramHeaders* ph) {
ELFProgramHeadersClear(ph);
Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
Elf32_Phdr* phdr = elf32_getphdr(elf->e);
ELFProgramHeadersResize(ph, hdr->e_phnum);
memcpy(ELFProgramHeadersGetPointer(ph, 0), phdr, sizeof(*phdr) * hdr->e_phnum);
}
void ELFGetSectionHeaders(struct ELF* elf, struct ELFSectionHeaders* sh) {
ELFSectionHeadersClear(sh);
Elf_Scn* section = elf_getscn(elf->e, 0);
do {
*ELFSectionHeadersAppend(sh) = *elf32_getshdr(section);
} while ((section = elf_nextscn(elf->e, section)));
}
Elf32_Shdr* ELFGetSectionHeader(struct ELF* elf, size_t index) {
Elf_Scn* section = elf_getscn(elf->e, index);
return elf32_getshdr(section);
}
size_t ELFFindSection(struct ELF* elf, const char* name) {
Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
size_t shstrtab = hdr->e_shstrndx;
if (strcmp(name, ".shstrtab") == 0) {
return shstrtab;
}
Elf_Scn* section = NULL;
while ((section = elf_nextscn(elf->e, section))) {
Elf32_Shdr* shdr = elf32_getshdr(section);
const char* sname = elf_strptr(elf->e, shstrtab, shdr->sh_name);
if (strcmp(sname, name) == 0) {
return elf_ndxscn(section);
}
}
return 0;
}
const char* ELFGetString(struct ELF* elf, size_t section, size_t string) {
return elf_strptr(elf->e, section, string);
}
#endif