Skip to content

Instantly share code, notes, and snippets.

@RKX1209
Last active March 10, 2018 22:12
Show Gist options
  • Save RKX1209/dd2fa8f2b406d5861ef1efc60095b9f8 to your computer and use it in GitHub Desktop.
Save RKX1209/dd2fa8f2b406d5861ef1efc60095b9f8 to your computer and use it in GitHub Desktop.
Unicorn ARM64 tracer patch, for debugging your own emulator (HEAD: Mephisto 6092782cc0e64f34aaa4eab623e7a8c518d1abc2)
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, &reg[0]);
+ uc_reg_read(uc, UC_ARM64_REG_X1, &reg[1]);
+ uc_reg_read(uc, UC_ARM64_REG_X2, &reg[2]);
+ uc_reg_read(uc, UC_ARM64_REG_X3, &reg[3]);
+ uc_reg_read(uc, UC_ARM64_REG_X4, &reg[4]);
+ uc_reg_read(uc, UC_ARM64_REG_X5, &reg[5]);
+ uc_reg_read(uc, UC_ARM64_REG_X6, &reg[6]);
+ uc_reg_read(uc, UC_ARM64_REG_X7, &reg[7]);
+ uc_reg_read(uc, UC_ARM64_REG_X8, &reg[8]);
+ uc_reg_read(uc, UC_ARM64_REG_X9, &reg[9]);
+ uc_reg_read(uc, UC_ARM64_REG_X10, &reg[10]);
+ uc_reg_read(uc, UC_ARM64_REG_X11, &reg[11]);
+ uc_reg_read(uc, UC_ARM64_REG_X12, &reg[12]);
+ uc_reg_read(uc, UC_ARM64_REG_X13, &reg[13]);
+ uc_reg_read(uc, UC_ARM64_REG_X14, &reg[14]);
+ uc_reg_read(uc, UC_ARM64_REG_X15, &reg[15]);
+ uc_reg_read(uc, UC_ARM64_REG_X16, &reg[16]);
+ uc_reg_read(uc, UC_ARM64_REG_X17, &reg[17]);
+ uc_reg_read(uc, UC_ARM64_REG_X18, &reg[18]);
+ uc_reg_read(uc, UC_ARM64_REG_X19, &reg[19]);
+ uc_reg_read(uc, UC_ARM64_REG_X20, &reg[20]);
+ uc_reg_read(uc, UC_ARM64_REG_X21, &reg[21]);
+ uc_reg_read(uc, UC_ARM64_REG_X22, &reg[22]);
+ uc_reg_read(uc, UC_ARM64_REG_X23, &reg[23]);
+ uc_reg_read(uc, UC_ARM64_REG_X24, &reg[24]);
+ uc_reg_read(uc, UC_ARM64_REG_X25, &reg[25]);
+ uc_reg_read(uc, UC_ARM64_REG_X26, &reg[26]);
+ uc_reg_read(uc, UC_ARM64_REG_X27, &reg[27]);
+ uc_reg_read(uc, UC_ARM64_REG_X28, &reg[28]);
+ uc_reg_read(uc, UC_ARM64_REG_X29, &reg[29]);
+ uc_reg_read(uc, UC_ARM64_REG_X30, &reg[30]);
+ //uc_reg_read(uc, UC_ARM64_REG_XZR, &reg[31]);
+ reg[31] = 0x0;
+ uc_reg_read(uc, UC_ARM64_REG_SP, &reg[32]);
+ uc_reg_read(uc, UC_ARM64_REG_PC, &reg[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