Last active
November 24, 2024 05:01
-
-
Save tekknolagi/73e75306d6a04887af0f631c0e919991 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile this with -rdynamic and your emulator .so with -fPIC -fpie -shared | |
#include <dlfcn.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include "dcheck.h" | |
static char logfile_name[] = "/tmp/gbtracer.log.XXXXXX"; | |
static int logfile_fd = 0; | |
static FILE* logfile_fp = NULL; | |
void gbtracer_open() { | |
fprintf(stderr, "gbtracer running...\n"); | |
logfile_fd = mkstemp(logfile_name); | |
DCHECK(logfile_fd != -1, "gbtracer_open could not make a logfile"); | |
logfile_fp = fdopen(logfile_fd, "w"); | |
DCHECK(logfile_fp != NULL, "gbtracer_open could not open logfile"); | |
} | |
void gbtracer_close() { | |
DCHECK(logfile_fd != -1, "gbtracer_close called before gbtracer_open"); | |
DCHECK(logfile_fp != NULL, "gbtracer_close called before gbtracer_open"); | |
fclose(logfile_fp); | |
close(logfile_fd); | |
fprintf(stderr, "gbtracer: %s\n", logfile_name); | |
} | |
static uint8_t gbtracer_h = 0; | |
static uint8_t gbtracer_l = 0; | |
static uint8_t gbtracer_a = 0; | |
static uint8_t gbtracer_b = 0; | |
static uint8_t gbtracer_c = 0; | |
static uint8_t gbtracer_d = 0; | |
static uint8_t gbtracer_e = 0; | |
static uint8_t gbtracer_f = 0; | |
static uint16_t gbtracer_sp = 0; | |
static uint16_t gbtracer_pc = 0; | |
static uint8_t* gbtracer_memory = NULL; | |
static size_t gbtracer_memory_size = 0; | |
#define WRITER(type, name) \ | |
void gbtracer_set_##name(type v) { gbtracer_##name = v; } | |
WRITER(uint8_t, h); | |
WRITER(uint8_t, l); | |
WRITER(uint8_t, a); | |
WRITER(uint8_t, b); | |
WRITER(uint8_t, c); | |
WRITER(uint8_t, d); | |
WRITER(uint8_t, e); | |
WRITER(uint8_t, f); | |
WRITER(uint16_t, sp); | |
#undef WRITER | |
void gbtracer_set_memory(uint8_t* memory, size_t size) { | |
gbtracer_memory = memory; | |
gbtracer_memory_size = size; | |
} | |
static void flush() { | |
fprintf(logfile_fp, "A: %02X ", gbtracer_a); | |
fprintf(logfile_fp, "F: %02X ", gbtracer_f); | |
fprintf(logfile_fp, "B: %02X ", gbtracer_b); | |
fprintf(logfile_fp, "C: %02X ", gbtracer_c); | |
fprintf(logfile_fp, "D: %02X ", gbtracer_d); | |
fprintf(logfile_fp, "E: %02X ", gbtracer_e); | |
fprintf(logfile_fp, "H: %02X ", gbtracer_h); | |
fprintf(logfile_fp, "L: %02X ", gbtracer_l); | |
fprintf(logfile_fp, "SP: %04X ", gbtracer_sp); | |
uint16_t pc = gbtracer_pc; | |
fprintf(logfile_fp, "PC: 00:%04X ", pc); | |
fprintf(logfile_fp, "("); | |
for (int i = 0; i < 4; i++) { | |
fprintf(logfile_fp, "%02X%s", gbtracer_memory[pc + i], i < 3 ? " " : ""); | |
} | |
fprintf(logfile_fp, ")"); | |
fprintf(logfile_fp, "\n"); | |
} | |
void gbtracer_set_pc(uint16_t pc) { | |
gbtracer_pc = pc; | |
flush(); | |
} | |
void gbtracer_sleep(int64_t) { | |
// Don't sleep in trace mode | |
} | |
int main(int argc, char** argv) { | |
if (argc < 2) { | |
printf("Usage: %s <program.so> [args...]\n", argv[0]); | |
return 1; | |
} | |
char* program = argv[1]; | |
int new_argc = argc - 1; | |
char** new_argv = argv + 1; | |
void* handle = dlopen(program, RTLD_NOW); | |
if (!handle) { | |
fprintf(stderr, "dlopen failed: %s\n", dlerror()); | |
return 1; | |
} | |
int (*entry)(int, char**) = dlsym(handle, "main"); | |
if (!entry) { | |
fprintf(stderr, "dlsym failed: %s\n", dlerror()); | |
return 1; | |
} | |
int result = entry(new_argc, new_argv); | |
int dlclose_result = dlclose(handle); | |
if (dlclose_result != 0) { | |
fprintf(stderr, "dlclose failed: %s\n", dlerror()); | |
return 1; | |
} | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment