Last active
March 10, 2018 22:12
-
-
Save RKX1209/dd2fa8f2b406d5861ef1efc60095b9f8 to your computer and use it in GitHub Desktop.
Unicorn ARM64 tracer patch, for debugging your own emulator (HEAD: Mephisto 6092782cc0e64f34aaa4eab623e7a8c518d1abc2)
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
diff --git a/Cpu.cpp b/Cpu.cpp | |
index 61c2aa7..64c9b8f 100644 | |
--- a/Cpu.cpp | |
+++ b/Cpu.cpp | |
@@ -1,4 +1,5 @@ | |
#include "Ctu.h" | |
+#define ARM64_REG_X(r) UC_ARM64_REG_X ## r | |
void intrHook(uc_engine *uc, uint32_t intNo, void *user_data) { | |
((Cpu *) user_data)->interruptHook(intNo); | |
@@ -8,6 +9,83 @@ bool unmpdHook(uc_engine *uc, uc_mem_type type, gptr addr, int size, guint value | |
return ((Cpu *) user_data)->unmappedHook(type, addr, size, value); | |
} | |
+extern FILE *traceOut; | |
+static void dumpReg (uc_engine *uc, Ctu *ctu) { | |
+ uint64_t reg[33]; | |
+ uc_reg_read(uc, UC_ARM64_REG_X0, ®[0]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X1, ®[1]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X2, ®[2]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X3, ®[3]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X4, ®[4]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X5, ®[5]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X6, ®[6]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X7, ®[7]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X8, ®[8]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X9, ®[9]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X10, ®[10]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X11, ®[11]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X12, ®[12]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X13, ®[13]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X14, ®[14]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X15, ®[15]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X16, ®[16]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X17, ®[17]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X18, ®[18]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X19, ®[19]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X20, ®[20]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X21, ®[21]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X22, ®[22]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X23, ®[23]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X24, ®[24]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X25, ®[25]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X26, ®[26]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X27, ®[27]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X28, ®[28]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X29, ®[29]); | |
+ uc_reg_read(uc, UC_ARM64_REG_X30, ®[30]); | |
+ //uc_reg_read(uc, UC_ARM64_REG_XZR, ®[31]); | |
+ reg[31] = 0x0; | |
+ uc_reg_read(uc, UC_ARM64_REG_SP, ®[32]); | |
+ uc_reg_read(uc, UC_ARM64_REG_PC, ®[33]); | |
+ | |
+ for (int r = 0; r <= 33; r++) { | |
+ char regc = 'X'; | |
+ if (r == 30) | |
+ regc = 'L'; | |
+ if (r == 31) | |
+ regc = 'S'; | |
+ if (r == 32) | |
+ regc = 'P'; | |
+ if (reg[r]) | |
+ printf ("\"%c%d\" : \"0x%016lx\"\n", regc, r, reg[r]); | |
+ if (r == 33) | |
+ fprintf (traceOut, "\"X%d\" : \"0x%016lx\"\n", r, reg[r]); | |
+ else | |
+ fprintf (traceOut, "\"X%d\" : \"0x%016lx\",\n", r, reg[r]); | |
+ } | |
+} | |
+ | |
+static uint64_t counter; | |
+void dumpMachine (uc_engine *uc, Ctu *ctu) { | |
+ fprintf (traceOut, "%lu : {\n", counter++); | |
+ dumpReg (uc, ctu); | |
+ fprintf (traceOut, "},\n"); | |
+} | |
+ | |
+// callback for tracing instruction | |
+void traceIns (uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { | |
+ auto ctu = (Ctu *) user_data; | |
+ if (traceOut) { | |
+ dumpMachine (uc, ctu); | |
+ } | |
+ uint32_t code = 0x0; | |
+ for (int i = 0; i < sizeof(code); i++) { | |
+ uint8_t byte; | |
+ uc_mem_read (uc, address + i, &byte, 1); | |
+ code |= (byte << (i * 8)); | |
+ } | |
+ printf("0x%lx: 0x%08x\n", address, code); | |
+} | |
void mmioHook(uc_engine *uc, uc_mem_type type, gptr address, int size, gptr value, void *user_data) { | |
gptr physicalAddress = ((Cpu *) user_data)->mmioHandler->getPhysicalAddressFromVirtual(address); | |
MmioBase *mmio = ((Cpu *) user_data)->mmioHandler->getMMIOFromPhysicalAddress(address); | |
@@ -52,6 +130,7 @@ Cpu::Cpu(Ctu *_ctu) : ctu(_ctu) { | |
uc_hook hookHandle; | |
CHECKED(uc_hook_add(uc, &hookHandle, UC_HOOK_INTR, (void *) intrHook, this, 0, -1)); | |
CHECKED(uc_hook_add(uc, &hookHandle, UC_HOOK_MEM_INVALID, (void *) unmpdHook, this, 0, -1)); | |
+ CHECKED(uc_hook_add(uc, &hookHandle, UC_HOOK_CODE, (void *) traceIns, this, 1, 0)); | |
for(auto i = 0; i < 0x80; ++i) | |
svcHandlers[i] = nullptr; | |
@@ -324,7 +403,7 @@ hook_t Cpu::addCodeBreakpoint(gptr addr) { | |
assert(ctu->gdbStub.enabled); | |
hook_t hookHandle; | |
- CHECKED(uc_hook_add(uc, &hookHandle, UC_HOOK_CODE, (void *)codeBpHook, ctu, addr, addr + 2)); | |
+ //CHECKED(uc_hook_add(uc, &hookHandle, UC_HOOK_CODE, (void *)codeBpHook, ctu, addr, addr + 2)); | |
return hookHandle; | |
} | |
diff --git a/Ctu.cpp b/Ctu.cpp | |
index a9f2b20..529f292 100644 | |
--- a/Ctu.cpp | |
+++ b/Ctu.cpp | |
@@ -7,15 +7,15 @@ Ctu::Ctu() : cpu(this), svc(this), ipc(this), tm(this), mmiohandler(this), bridg | |
} | |
void Ctu::execProgram(gptr ep) { | |
- auto sp = 7 << 24; | |
- auto ss = 8 * 1024 * 1024; | |
- | |
- cpu.map(sp - ss, ss); | |
+ // auto sp = 7 << 24; | |
+ auto sp = 0x3000000; | |
+ auto ss = 0x1000000; | |
+ cpu.map(sp, ss); | |
cpu.setMmio(&mmiohandler); | |
mmiohandler.MMIOInitialize(); | |
- auto mainThread = tm.create(ep, sp); | |
- mainThread->regs.X1 = mainThread->handle; | |
+ auto mainThread = tm.create(ep, sp + 0x100000); | |
+ //mainThread->regs.X1 = mainThread->handle; | |
mainThread->resume(); | |
tm.start(); | |
diff --git a/Ctu.h b/Ctu.h | |
index 0915dc0..7a79d0b 100644 | |
--- a/Ctu.h | |
+++ b/Ctu.h | |
@@ -1,4 +1,5 @@ | |
-#pragma once | |
+#ifndef __CTU_H | |
+#define __CTU_H | |
#include <byteswap.h> | |
#include <netinet/in.h> | |
@@ -52,10 +53,10 @@ const gptr TERMADDR = 1ULL << 61; | |
#define LONGFMT "%lx" | |
enum LogLevel { | |
- None = 0, | |
- Error = 1, | |
- Warn = 2, | |
- Debug = 3, | |
+ None = 0, | |
+ Error = 1, | |
+ Warn = 2, | |
+ Debug = 3, | |
Info = 4 | |
}; | |
@@ -164,10 +165,12 @@ public: | |
gptr loadbase, loadsize; | |
bool socketsEnabled; | |
- | |
+ | |
private: | |
ghandle handleId; | |
unordered_map<ghandle, shared_ptr<KObject>> handles; | |
}; | |
#include "IpcStubs.h" | |
+ | |
+#endif | |
diff --git a/Makefile b/Makefile | |
index 14d1e1b..fb53180 100644 | |
--- a/Makefile | |
+++ b/Makefile | |
@@ -4,7 +4,7 @@ CPP_FILES := $(wildcard *.cpp) | |
IPCIMPL_FILES := $(wildcard ipcimpl/*.cpp) | |
H_FILES := $(wildcard *.h) | |
ID_FILES := $(wildcard ipcdefs/*.id) | |
-CC_FLAGS := -std=c++1z -I. -Weverything -Werror -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-header-hygiene -Wno-shadow-field-in-constructor -Wno-old-style-cast -Wno-missing-prototypes -Wno-unused-parameter -Wno-padded -Wno-sign-conversion -Wno-sign-compare -Wno-shadow-uncaptured-local -Wno-weak-vtables -Wno-switch -Wno-unused-variable -Wno-unused-private-field -Wno-variadic-macros -Wno-unused-macros -Wno-gnu-anonymous-struct -Wno-nested-anon-types -Wno-reorder -Wno-missing-noreturn -Wno-unreachable-code -Wno-gnu-zero-variadic-macro-arguments -Wno-cast-align -DLZ4_DISABLE_DEPRECATE_WARNINGS -Wno-undefined-func-template -Wno-format-nonliteral -Wno-documentation-unknown-command $(EXTRA_CC_FLAGS) | |
+CC_FLAGS := -std=c++1z -O0 -I. $(EXTRA_CC_FLAGS) | |
LD_FLAGS := -lunicorn -lpthread -llz4 $(EXTRA_LD_FLAGS) | |
OBJ_FILES := $(CPP_FILES:.cpp=.o) $(IPCIMPL_FILES:.cpp=.o) | |
diff --git a/Nxo.cpp b/Nxo.cpp | |
index a9524dd..93ae73c 100644 | |
--- a/Nxo.cpp | |
+++ b/Nxo.cpp | |
@@ -37,9 +37,10 @@ guint Nso::load(Ctu &ctu, gptr base, bool relocate) { | |
tsize = (tsize & ~0xFFF) + 0x1000; | |
ctu.cpu.map(base, tsize); | |
- | |
+ printf("mapped 0x%lx: size 0x%lx\n", base, tsize); | |
char *text = decompress(fp, hdr.textOff, hdr.rdataOff - hdr.textOff, hdr.textSize); | |
ctu.cpu.writemem(base + hdr.textLoc, text, hdr.textSize); | |
+ printf ("textloc 0x%016x\n", hdr.textLoc); | |
delete[] text; | |
char *rdata = decompress(fp, hdr.rdataOff, hdr.dataOff - hdr.rdataOff, hdr.rdataSize); | |
@@ -94,7 +95,7 @@ guint Nro::load(Ctu &ctu, gptr base, bool relocate) { | |
char *image = new char[hdr.fileSize]; | |
fp.seekg(0); | |
fp.read(image, hdr.fileSize); | |
- | |
+ | |
if(relocate) { | |
// stupid tiny linker | |
ModuleHeader moduleHeader = *(ModuleHeader*) (image + hdr.moduleHeaderOff); | |
@@ -105,7 +106,7 @@ guint Nro::load(Ctu &ctu, gptr base, bool relocate) { | |
uint64_t relaEnt = 0; | |
uint64_t relaCount = 0; | |
bool foundRela = false; | |
- | |
+ | |
while(dynamic->d_tag > 0) { | |
switch(dynamic->d_tag) { | |
case 7: // DT_RELA | |
@@ -141,11 +142,11 @@ guint Nro::load(Ctu &ctu, gptr base, bool relocate) { | |
if(relaSize != relaCount * relaEnt) { | |
LOG_ERROR(TLD, "relaSize mismatch"); | |
} | |
- | |
+ | |
Elf64_Rela *relaBase = (Elf64_Rela*) (image + relaOffset); | |
for(int i = 0; i < relaCount; i++) { | |
Elf64_Rela rela = relaBase[i]; | |
- | |
+ | |
switch(rela.r_reloc_type) { | |
case 0x403: // R_AARCH64_RELATIVE | |
if(rela.r_symbol != 0) { | |
@@ -158,9 +159,9 @@ guint Nro::load(Ctu &ctu, gptr base, bool relocate) { | |
} | |
} | |
} | |
- | |
+ | |
ctu.cpu.writemem(base, image, hdr.fileSize); | |
delete[] image; | |
- | |
+ | |
return tsize; | |
} | |
diff --git a/ThreadManager.cpp b/ThreadManager.cpp | |
index 7582f88..cb1f8d9 100644 | |
--- a/ThreadManager.cpp | |
+++ b/ThreadManager.cpp | |
@@ -130,7 +130,7 @@ shared_ptr<Thread> ThreadManager::create(gptr pc, gptr sp) { | |
threads[thread->id] = thread; | |
thread->regs.PC = pc; | |
thread->regs.SP = sp; | |
- thread->regs.X30 = TERMADDR; | |
+ //thread->regs.X30 = TERMADDR; | |
return thread; | |
} | |
diff --git a/main.cpp b/main.cpp | |
index 20978a3..5431723 100644 | |
--- a/main.cpp | |
+++ b/main.cpp | |
@@ -38,7 +38,7 @@ struct Arg: public option::Arg | |
} | |
}; | |
-enum optionIndex { UNKNOWN, HELP, ENABLE_GDB, PORT, NSO, NRO, ENABLE_SOCKETS }; | |
+enum optionIndex { UNKNOWN, HELP, ENABLE_GDB, PORT, NSO, NRO, ENABLE_SOCKETS, ENABLE_TRACE }; | |
const option::Descriptor usage[] = | |
{ | |
{UNKNOWN, 0, "", "",Arg::None, "USAGE: ctu [options] <load-directory>\n\n" | |
@@ -49,6 +49,7 @@ const option::Descriptor usage[] = | |
{NSO, 0,"","load-nso",Arg::NonEmpty, " --load-nso \tLoad an NSO without load directory"}, | |
{NRO, 0,"","load-nro",Arg::NonEmpty, " --load-nro \tLoad an NRO without load directory (entry point .text+0x80)"}, | |
{ENABLE_SOCKETS, 0, "b","enable-sockets",Arg::None, " -- enable-sockets, -b \tEnable BSD socket passthrough." }, | |
+ {ENABLE_TRACE, 0, "t","enable-trace",Arg::None, " --enable-trace, -t \tEnable Trace" }, | |
{0,0,nullptr,nullptr,nullptr,nullptr} | |
}; | |
@@ -93,6 +94,18 @@ void runLisp(Ctu &ctu, const string &dir, shared_ptr<Atom> code) { | |
LOG_ERROR(Main, "Unknown function in load script: '%s'", head->strVal.c_str()); | |
} | |
+FILE *traceOut = NULL; | |
+static void initTrace(Ctu &ctu, const char *ofile) { | |
+ if ((traceOut = fopen(ofile, "w")) == NULL) { | |
+ fprintf(stderr, "Can not open output file for trace\n"); | |
+ exit(EXIT_FAILURE); | |
+ } | |
+} | |
+ | |
+static void finTrace(Ctu &ctu) { | |
+ fclose (traceOut); | |
+} | |
+ | |
int main(int argc, char **argv) { | |
argc -= argc > 0; | |
argv += argc > 0; | |
@@ -137,13 +150,19 @@ int main(int argc, char **argv) { | |
} else { | |
ctu.socketsEnabled = false; | |
} | |
- | |
+ | |
+ if(options[ENABLE_TRACE].count()) { | |
+ initTrace (ctu, "unicorn_trace.json"); | |
+ printf("trace enabled\n"); | |
+ } | |
+ //gptr start = 0x7100000000; | |
+ gptr start = 0x0; | |
if(options[NSO].count()) { | |
- loadNso(ctu, options[NSO][0].arg, 0x7100000000); | |
- ctu.execProgram(0x7100000000); | |
+ loadNso(ctu, options[NSO][0].arg, start); | |
+ ctu.execProgram(start); | |
} else if(options[NRO].count()) { | |
- loadNro(ctu, options[NRO][0].arg, 0x7100000000); | |
- ctu.execProgram(0x7100000080); | |
+ loadNro(ctu, options[NRO][0].arg, start); | |
+ ctu.execProgram(start + 0x80); | |
} else { | |
string dir = parse.nonOption(0); | |
auto lfn = dir + "/load.meph"; | |
@@ -158,5 +177,8 @@ int main(int argc, char **argv) { | |
runLisp(ctu, dir, elem); | |
} | |
+ if (traceOut) { | |
+ finTrace (ctu); | |
+ } | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment