mirror of
https://github.com/wiiu-env/gdbstub_plugin.git
synced 2024-11-22 11:49:14 +01:00
Add files
This commit is contained in:
parent
1fe0c1c77d
commit
bbf63715e9
16
build.py
Normal file
16
build.py
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
PPC_GCC = r"C:\devkitPro\devkitPPC\bin\powerpc-eabi-g++"
|
||||
|
||||
files = []
|
||||
for dirname, subdirs, subfiles in os.walk("src"):
|
||||
for filename in subfiles:
|
||||
if filename.endswith(".cpp") or filename.endswith(".c") or \
|
||||
filename.endswith(".S") or filename.endswith(".s"):
|
||||
filepath = os.path.join(dirname, filename)
|
||||
files.append(filepath)
|
||||
|
||||
args = "-O2 -Isrc -fno-exceptions -nostartfiles -T src/link.ld -Wl,-n -Wl,--gc-sections"
|
||||
subprocess.call("%s %s %s" %(PPC_GCC, args, " ".join(files)))
|
940
disassemble.py
Normal file
940
disassemble.py
Normal file
@ -0,0 +1,940 @@
|
||||
|
||||
trap_condition_table = {
|
||||
1: "lgt",
|
||||
2: "llt",
|
||||
4: "eq",
|
||||
5: "lge",
|
||||
6: "lle",
|
||||
8: "gt",
|
||||
12: "ge",
|
||||
16: "lt",
|
||||
20: "le",
|
||||
24: "ne",
|
||||
31: "u"
|
||||
}
|
||||
|
||||
spr_table_suffix = {
|
||||
1: "xer",
|
||||
8: "lr",
|
||||
9: "ctr"
|
||||
}
|
||||
|
||||
spr_table = {}
|
||||
|
||||
def decodeI(value):
|
||||
return (value >> 2) & 0xFFFFFF, (value >> 1) & 1, value & 1
|
||||
|
||||
def decodeB(value):
|
||||
return (value >> 21) & 0x1F, (value >> 16) & 0x1F, (value >> 2) & 0x3FFF, (value >> 1) & 1, value & 1
|
||||
|
||||
def decodeD(value):
|
||||
return (value >> 21) & 0x1F, (value >> 16) & 0x1F, value & 0xFFFF
|
||||
|
||||
def decodeX(value):
|
||||
return (value >> 21) & 0x1F, (value >> 16) & 0x1F, (value >> 11) & 0x1F, value & 1
|
||||
|
||||
def decodeABC(value):
|
||||
return (value >> 21) & 0x1F, (value >> 16) & 0x1F, (value >> 11) & 0x1F, (value >> 6) & 0x1F, value & 1
|
||||
|
||||
def decodeR(value):
|
||||
return (value >> 21) & 0x1F, (value >> 16) & 0x1F, (value >> 11) & 0x1F, (value >> 6) & 0x1F, (value >> 1) & 0x1F, value & 1
|
||||
|
||||
def extend_sign(value, bits=16):
|
||||
if value & 1 << (bits - 1):
|
||||
value -= 1 << bits
|
||||
return value
|
||||
|
||||
def ihex(value):
|
||||
sign = "-" if value < 0 else ""
|
||||
return "%s0x%X" %(sign, value)
|
||||
|
||||
|
||||
condition_table_true = ["lt", "gt", "eq"]
|
||||
condition_table_false = ["ge", "le", "ne"]
|
||||
|
||||
def decode_cond_true(BI):
|
||||
if BI % 4 < 3:
|
||||
return condition_table_true[BI % 4]
|
||||
|
||||
def decode_cond_false(BI):
|
||||
if BI % 4 < 3:
|
||||
return condition_table_false[BI % 4]
|
||||
|
||||
def decode_cond(BO, BI):
|
||||
ctr = ""
|
||||
if not BO & 4:
|
||||
if BO & 2:
|
||||
ctr = "dz"
|
||||
else:
|
||||
ctr = "dnz"
|
||||
|
||||
cond = ""
|
||||
if not BO & 16:
|
||||
if BO & 8:
|
||||
cond = decode_cond_true(BI)
|
||||
else:
|
||||
cond = decode_cond_false(BI)
|
||||
|
||||
if cond is not None:
|
||||
return ctr + cond
|
||||
|
||||
|
||||
NO_SWAP = False
|
||||
SWAP = True
|
||||
|
||||
UNSIGNED = False
|
||||
SIGNED = True
|
||||
|
||||
def decode_simple(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if D or A or B or Rc:
|
||||
return "???"
|
||||
return instr
|
||||
return decode
|
||||
|
||||
def decode_triple_reg(instr, swap):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if swap:
|
||||
D, A = A, D
|
||||
return "%s%s" %(instr, "." * Rc), "r%i, r%i, r%i" %(D, A, B)
|
||||
return decode
|
||||
|
||||
def decode_double_reg(instr, swap):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if B != 0:
|
||||
return "???"
|
||||
if swap:
|
||||
D, A = A, D
|
||||
return "%s%s" %(instr, "." * Rc), "r%i, r%i" %(D, A)
|
||||
return decode
|
||||
|
||||
def decode_single_reg(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if A or B or Rc:
|
||||
return "???"
|
||||
return instr, "r%i" %D
|
||||
return decode
|
||||
|
||||
def decode_double_reg_imm(instr, sign, swap):
|
||||
def decode(value, addr):
|
||||
D, A, IMM = decodeD(value)
|
||||
if sign:
|
||||
IMM = extend_sign(IMM)
|
||||
if swap:
|
||||
D, A = A, D
|
||||
return instr, "r%i, r%i, %s" %(D, A, ihex(IMM))
|
||||
return decode
|
||||
|
||||
def decode_triple_cr(instr, simple1, simple2):
|
||||
def decode(value, addr):
|
||||
D, A, B, pad = decodeX(value)
|
||||
if pad:
|
||||
return "???"
|
||||
if D == A == B and simple1:
|
||||
return simple1, "cr%i" %D
|
||||
if A == B and simple2:
|
||||
return simple2, "cr%i, cr%i" %(D, A)
|
||||
return instr, "cr%i, cr%i, cr%i" %(D, A, B)
|
||||
return decode
|
||||
|
||||
def decode_single_cr(instr, rc_ok):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if A or B or (Rc and not rc_ok):
|
||||
return "???"
|
||||
return instr + "." * Rc, "cr%i" %D
|
||||
return decode
|
||||
|
||||
def decode_compare_reg(instr):
|
||||
def decode(value, addr):
|
||||
cr, A, B, pad = decodeX(value)
|
||||
if cr & 3 or pad:
|
||||
return "???"
|
||||
|
||||
if cr == 0:
|
||||
return instr, "r%i, r%i" %(A, B)
|
||||
return instr, "cr%i, r%i, r%i" %(cr >> 2, A, B)
|
||||
return decode
|
||||
|
||||
def decode_compare_imm(instr, sign):
|
||||
def decode(value, addr):
|
||||
cr, A, IMM = decodeD(value)
|
||||
if cr & 3:
|
||||
return "???"
|
||||
|
||||
if sign:
|
||||
IMM = extend_sign(IMM)
|
||||
|
||||
if cr == 0:
|
||||
return instr, "r%i, %s" %(A, ihex(IMM))
|
||||
return instr, "cr%i, r%i, %s" %(cr >> 2, A, ihex(IMM))
|
||||
return decode
|
||||
|
||||
def decode_branch_to_reg(reg):
|
||||
def decode(value, addr):
|
||||
BO, BI, pad, LK = decodeX(value)
|
||||
if pad:
|
||||
return "???"
|
||||
|
||||
cond = decode_cond(BO, BI)
|
||||
suffix = "l" * LK
|
||||
|
||||
if cond is None:
|
||||
return "bc%s%s" %(reg, suffix), "%i, %i" %(BO, BI)
|
||||
|
||||
instr = "b%s%s%s" %(cond, reg, suffix)
|
||||
if BI >= 4:
|
||||
return instr, "cr%i" %(BI // 4)
|
||||
return instr
|
||||
return decode
|
||||
|
||||
def decode_double_float(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if A != 0:
|
||||
return "???"
|
||||
return "%s%s" %(instr, "." * Rc), "f%i, f%i" %(D, B)
|
||||
return decode
|
||||
|
||||
def decode_triple_float(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
return "%s%s" %(instr, "." * Rc), "f%i, f%i, f%i" %(D, A, B)
|
||||
return decode
|
||||
|
||||
def decode_triple_float_alt(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, C, Rc = decodeABC(value)
|
||||
if B != 0:
|
||||
return "???"
|
||||
return "%s%s" %(instr, "." * Rc), "f%i, f%i, f%i" %(D, A, C)
|
||||
return decode
|
||||
|
||||
def decode_quad_float(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, C, Rc = decodeABC(value)
|
||||
return "%s%s" %(instr, "." * Rc), "f%i, f%i, f%i, f%i" %(D, A, C, B)
|
||||
return decode
|
||||
|
||||
def decode_compare_float(instr):
|
||||
def decode(value, addr):
|
||||
cr, A, B, pad = decodeX(value)
|
||||
if cr & 3 or pad:
|
||||
return "???"
|
||||
return instr, "cr%i, f%i, f%i" %(cr >> 2, A, B)
|
||||
return decode
|
||||
|
||||
def decode_memory(instr):
|
||||
def decode(value, addr):
|
||||
D, A, d = decodeD(value)
|
||||
A = extend_sign(A)
|
||||
return instr, "r%i, %s(r%i)" %(D, ihex(d), A)
|
||||
return decode
|
||||
|
||||
def decode_memory_indexed(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if Rc:
|
||||
return "???"
|
||||
if A == 0:
|
||||
return instr, "r%i, 0, r%i" %(D, B)
|
||||
return instr, "r%i, r%i, r%i" %(D, A, B)
|
||||
return decode
|
||||
|
||||
def decode_memory_float(instr):
|
||||
def decode(value, addr):
|
||||
D, A, d = decodeD(value)
|
||||
A = extend_sign(A)
|
||||
return instr, "f%i, %s(r%i)" %(D, ihex(d), A)
|
||||
return decode
|
||||
|
||||
def decode_memory_float_indexed(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if Rc:
|
||||
return "???"
|
||||
if A == 0:
|
||||
return instr, "f%i, 0, r%i" %(D, B)
|
||||
return instr, "f%i, r%i, r%i" %(D, A, B)
|
||||
return decode
|
||||
|
||||
def decode_cache(instr):
|
||||
def decode(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if D != 0 or Rc != 0:
|
||||
return "???"
|
||||
return instr, "r%i, r%i" %(A, B)
|
||||
return decode
|
||||
|
||||
|
||||
add = decode_triple_reg("add", NO_SWAP)
|
||||
addc = decode_triple_reg("addc", NO_SWAP)
|
||||
adde = decode_triple_reg("adde", NO_SWAP)
|
||||
|
||||
def addi(value, addr):
|
||||
D, A, SIMM = decodeD(value)
|
||||
SIMM = extend_sign(SIMM)
|
||||
if A == 0:
|
||||
return "li", "r%i, %s" %(D, ihex(SIMM))
|
||||
return "addi", "r%i, r%i, %s" %(D, A, ihex(SIMM))
|
||||
|
||||
addic = decode_double_reg_imm("addic", SIGNED, NO_SWAP)
|
||||
addic_ = decode_double_reg_imm("addic.", SIGNED, NO_SWAP)
|
||||
|
||||
def addis(value, addr):
|
||||
D, A, SIMM = decodeD(value)
|
||||
SIMM = extend_sign(SIMM)
|
||||
if A == 0:
|
||||
return "lis", "r%i, %s" %(D, ihex(SIMM))
|
||||
return "addis", "r%i, r%i, %s" %(D, A, ihex(SIMM))
|
||||
|
||||
addme = decode_double_reg("addme", NO_SWAP)
|
||||
addze = decode_double_reg("addze", NO_SWAP)
|
||||
|
||||
and_ = decode_triple_reg("and", SWAP)
|
||||
andc = decode_triple_reg("andc", SWAP)
|
||||
andi = decode_double_reg_imm("andi.", UNSIGNED, SWAP)
|
||||
andis = decode_double_reg_imm("andis.", UNSIGNED, SWAP)
|
||||
|
||||
def b(value, addr):
|
||||
LI, AA, LK = decodeI(value)
|
||||
LI = extend_sign(LI, 24) * 4
|
||||
if AA: dst = LI
|
||||
else:
|
||||
dst = addr + LI
|
||||
return "b%s%s" %("l" * LK, "a" * AA), ihex(dst)
|
||||
|
||||
def bc(value, addr):
|
||||
BO, BI, BD, AA, LK = decodeB(value)
|
||||
BD = extend_sign(BD, 14) * 4
|
||||
|
||||
suffix = "%s%s" %("l" * LK, "a" * AA)
|
||||
|
||||
if AA: dst = BD
|
||||
else:
|
||||
dst = addr + BD
|
||||
|
||||
cond = decode_cond(BO, BI)
|
||||
if cond is None:
|
||||
return "bc" + suffix, "%i, %i, %s" %(BO, BI, ihex(dst))
|
||||
if BI >= 4:
|
||||
return "b" + cond + suffix, "cr%i, %s" %(BI // 4, ihex(dst))
|
||||
return "b" + cond + suffix, ihex(dst)
|
||||
|
||||
bcctr = decode_branch_to_reg("ctr")
|
||||
bclr = decode_branch_to_reg("lr")
|
||||
|
||||
cmp = decode_compare_reg("cmpw")
|
||||
cmpi = decode_compare_imm("cmpwi", SIGNED)
|
||||
cmpl = decode_compare_reg("cmplw")
|
||||
cmpli = decode_compare_imm("cmplwi", UNSIGNED)
|
||||
|
||||
cntlzw = decode_double_reg("cntlzw", SWAP)
|
||||
|
||||
crand = decode_triple_cr("crand", None, None)
|
||||
crandc = decode_triple_cr("crandc", None, None)
|
||||
creqv = decode_triple_cr("creqv", "crset", None)
|
||||
crnand = decode_triple_cr("crnand", None, None)
|
||||
crnor = decode_triple_cr("crnor", None, "crnot")
|
||||
cror = decode_triple_cr("cror", None, "crmove")
|
||||
crorc = decode_triple_cr("crorc", None, None)
|
||||
crxor = decode_triple_cr("crxor", "crclr", None)
|
||||
|
||||
dcba = decode_cache("dcba")
|
||||
dcbf = decode_cache("dcbf")
|
||||
dcbi = decode_cache("dcbi")
|
||||
dcbst = decode_cache("dcbst")
|
||||
dcbt = decode_cache("dcbt")
|
||||
dcbtst = decode_cache("dcbtst")
|
||||
dcbz = decode_cache("dcbz")
|
||||
|
||||
divw = decode_triple_reg("divw", NO_SWAP)
|
||||
divwu = decode_triple_reg("divwu", NO_SWAP)
|
||||
|
||||
eieio = decode_simple("eieio")
|
||||
|
||||
eqv = decode_triple_reg("eqv", SWAP)
|
||||
|
||||
extsb = decode_double_reg("extsb", SWAP)
|
||||
extsh = decode_double_reg("extsh", SWAP)
|
||||
|
||||
fabs = decode_double_float("fabs")
|
||||
fadd = decode_triple_float("fadd")
|
||||
fadds = decode_triple_float("fadds")
|
||||
fcmpo = decode_compare_float("fcmpo")
|
||||
fcmpu = decode_compare_float("fcmpu")
|
||||
fctiw = decode_double_float("fctiw")
|
||||
fctiwz = decode_double_float("fctiwz")
|
||||
fdiv = decode_triple_float("fdiv")
|
||||
fdivs = decode_triple_float("fdivs")
|
||||
fmadd = decode_quad_float("fmadd")
|
||||
fmadds = decode_quad_float("fmadds")
|
||||
fmr = decode_double_float("fmr")
|
||||
fmsub = decode_quad_float("fmsub")
|
||||
fmsubs = decode_quad_float("fmsubs")
|
||||
fmul = decode_triple_float_alt("fmul")
|
||||
fmuls = decode_triple_float_alt("fmuls")
|
||||
fnabs = decode_double_float("fnabs")
|
||||
fneg = decode_double_float("fneg")
|
||||
fnmadd = decode_quad_float("fnmadd")
|
||||
fnmadds = decode_quad_float("fnmadds")
|
||||
fnmsub = decode_quad_float("fnmsub")
|
||||
fnmsubs = decode_quad_float("fnmsubs")
|
||||
fres = decode_double_float("fres")
|
||||
frsp = decode_double_float("frsp")
|
||||
fsel = decode_quad_float("fsel")
|
||||
fsqrte = decode_double_float("fsqrte")
|
||||
fsqrt = decode_double_float("fsqrt")
|
||||
fsqrts = decode_double_float("fsqrts")
|
||||
fsub = decode_triple_float("fsub")
|
||||
fsubs = decode_triple_float("fsubs")
|
||||
|
||||
icbi = decode_cache("icbi")
|
||||
isync = decode_simple("isync")
|
||||
|
||||
lbz = decode_memory("lbz")
|
||||
lbzu = decode_memory("lbzu")
|
||||
lbzux = decode_memory_indexed("lbzux")
|
||||
lbzx = decode_memory_indexed("lbzx")
|
||||
lfd = decode_memory_float("lfd")
|
||||
lfdu = decode_memory_float("lfdu")
|
||||
lfdux = decode_memory_float_indexed("lfdux")
|
||||
lfdx = decode_memory_float_indexed("lfdx")
|
||||
lfs = decode_memory_float("lfs")
|
||||
lfsu = decode_memory_float("lfsu")
|
||||
lfsux = decode_memory_float_indexed("lfsux")
|
||||
lfsx = decode_memory_float_indexed("lfsx")
|
||||
lha = decode_memory("lha")
|
||||
lhau = decode_memory("lhau")
|
||||
lhaux = decode_memory_indexed("lhaux")
|
||||
lhax = decode_memory_indexed("lhax")
|
||||
lhbrx = decode_memory_indexed("lhbrx")
|
||||
lhz = decode_memory("lhz")
|
||||
lhzu = decode_memory("lhzu")
|
||||
lhzux = decode_memory_indexed("lhzux")
|
||||
lhzx = decode_memory_indexed("lhzx")
|
||||
lmw = decode_memory("lmw")
|
||||
|
||||
def lswi(value, addr):
|
||||
D, A, NB, Rc = decodeX(value)
|
||||
if Rc:
|
||||
return "???"
|
||||
return "lswi", "r%i, r%i, %i" %(D, A, NB)
|
||||
|
||||
lswx = decode_memory_indexed("lswx")
|
||||
lwarx = decode_memory_indexed("lwarx")
|
||||
lwbrx = decode_memory_indexed("lwbrx")
|
||||
lwz = decode_memory("lwz")
|
||||
lwzu = decode_memory("lwzu")
|
||||
lwzux = decode_memory_indexed("lwzux")
|
||||
lwzx = decode_memory_indexed("lwzx")
|
||||
|
||||
def mcrf(value, addr):
|
||||
crD, crS, pad1, pad2 = decodeX(value)
|
||||
if crD & 3 or crS & 3 or pad1 or pad2:
|
||||
return "???"
|
||||
return "mcrf", "cr%i, cr%i" %(crD, crS)
|
||||
|
||||
def mcrfs(value, addr):
|
||||
crD, crS, pad1, pad2 = decodeX(value)
|
||||
if crD & 3 or crS & 3 or pad1 or pad2:
|
||||
return "???"
|
||||
return "mcrfs", "cr%i, cr%i" %(crD, crS)
|
||||
|
||||
mcrxr = decode_single_cr("mcrxr", False)
|
||||
|
||||
mfcr = decode_single_reg("mfcr")
|
||||
|
||||
def mffs(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if A or B:
|
||||
return "???"
|
||||
return "mffs%s" %("." * Rc), "f%i" %D
|
||||
|
||||
mfmsr = decode_single_reg("mfmsr")
|
||||
|
||||
def mfspr(value, addr):
|
||||
D, lo, hi, pad = decodeX(value)
|
||||
spr = (hi << 5) | lo
|
||||
|
||||
if pad:
|
||||
return "???"
|
||||
|
||||
if spr in spr_table_suffix:
|
||||
return "mf%s" %spr_table_suffix[spr], "r%i" %D
|
||||
if spr in spr_table:
|
||||
return "mfspr", "r%i, %s" %(D, spr_table[spr])
|
||||
return "mfspr", "r%i, %i" %(D, spr)
|
||||
|
||||
def mfsr(value, addr):
|
||||
D, SR, pad1, pad2 = decodeX(value)
|
||||
if pad1 or pad2 or SR > 15:
|
||||
return "???"
|
||||
return "mfsr", "r%i, %i" %(D, SR)
|
||||
|
||||
def mfsrin(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if A or Rc:
|
||||
return "???"
|
||||
return "mfsrin", "r%i, r%i" %(D, B)
|
||||
|
||||
def mftb(value, addr):
|
||||
D, lo, hi, pad = decodeX(value)
|
||||
tbr = (hi << 5) | lo
|
||||
|
||||
if pad:
|
||||
return "???"
|
||||
|
||||
if tbr == 268: return "mftb", "r%i" %D
|
||||
if tbr == 269: return "mftbu", "r%i" %D
|
||||
return "???"
|
||||
|
||||
def mtcrf(value, addr):
|
||||
S, hi, lo, pad = decodeX(value)
|
||||
if lo & 1 or hi & 16 or pad:
|
||||
return "???"
|
||||
mask = (hi << 4) | (lo >> 1)
|
||||
if mask == 0xFF:
|
||||
return "mtcr", "r%i" %S
|
||||
return "mtcrf", "%s, r%i" %(ihex(mask), S)
|
||||
|
||||
mtfsb0 = decode_single_cr("mtfsb0", True)
|
||||
mtfsb1 = decode_single_cr("mtfsb1", True)
|
||||
|
||||
def mtfsf(value, addr):
|
||||
hi, lo, B, Rc = decodeX(value)
|
||||
if lo & 1 or hi & 16:
|
||||
return "???"
|
||||
mask = (hi << 4) | (lo >> 1)
|
||||
return "mtfsf" + "." * Rc, "%s, f%i" %(ihex(mask), B)
|
||||
|
||||
def mtfsfi(value, addr):
|
||||
cr, pad, IMM, Rc = decodeX(value)
|
||||
if cr & 3 or pad or IMM & 1:
|
||||
return "???"
|
||||
return "mtfsfi" + "." * Rc, "cr%i, %i" %(cr >> 2, IMM >> 1)
|
||||
|
||||
mtmsr = decode_single_reg("mtmsr")
|
||||
|
||||
def mtspr(value, addr):
|
||||
S, lo, hi, pad = decodeX(value)
|
||||
spr = (hi << 5) | lo
|
||||
|
||||
if pad:
|
||||
return "???"
|
||||
|
||||
if spr in spr_table_suffix:
|
||||
return "mt%s" %spr_table_suffix[spr], "r%i" %S
|
||||
if spr in spr_table:
|
||||
return "mtspr", "%s, r%i" %(spr_table[spr], S)
|
||||
return "mtspr", "%i, r%i" %(spr, S)
|
||||
|
||||
def mtsr(value, addr):
|
||||
S, SR, pad1, pad2 = decodeX(value)
|
||||
if pad1 or pad2 or SR > 15:
|
||||
return "???"
|
||||
return "mtsr", "%i, %ri" %(SR, S)
|
||||
|
||||
def mtsrin(value, addr):
|
||||
S, A, B, Rc = decodeX(value)
|
||||
if A or Rc:
|
||||
return "???"
|
||||
return "mtsrin", "r%i, r%i" %(S, B)
|
||||
|
||||
mulhw = decode_triple_reg("mulhw", NO_SWAP)
|
||||
mulhwu = decode_triple_reg("mulhwu", NO_SWAP)
|
||||
mulli = decode_double_reg_imm("mulli", SIGNED, NO_SWAP)
|
||||
mullwu = decode_triple_reg("mullwu", NO_SWAP)
|
||||
nand = decode_triple_reg("nand", SWAP)
|
||||
neg = decode_double_reg("neg", NO_SWAP)
|
||||
|
||||
def nor(value, addr):
|
||||
S, A, B, Rc = decodeX(value)
|
||||
if S == B:
|
||||
return "not" + "." * Rc, "r%i, r%i" %(A, S)
|
||||
return "nor" + "." * Rc, "r%i, r%i, r%i" %(A, S, B)
|
||||
|
||||
def or_(value, addr):
|
||||
S, A, B, Rc = decodeX(value)
|
||||
if S == B:
|
||||
return "mr" + "." * Rc, "r%i, r%i" %(A, S)
|
||||
return "or" + "." * Rc, "r%i, r%i, r%i" %(A, S, B)
|
||||
|
||||
orc = decode_triple_reg("orc", SWAP)
|
||||
|
||||
def ori(value, addr):
|
||||
S, A, UIMM = decodeD(value)
|
||||
if UIMM == 0:
|
||||
return "nop"
|
||||
return "ori", "r%i, r%i, %s" %(A, S, ihex(UIMM))
|
||||
|
||||
oris = decode_double_reg_imm("oris", UNSIGNED, SWAP)
|
||||
|
||||
rfi = decode_simple("rfi")
|
||||
|
||||
def rlwimi(value, addr):
|
||||
S, A, SH, MB, ME, Rc = decodeR(value)
|
||||
suffix = "." * Rc
|
||||
if SH == 32 - MB and ME >= MB:
|
||||
return "inslwi" + suffix, "r%i, r%i, %i, %i" %(A, S, ME - MB + 1, MB)
|
||||
if MB < 31 and SH + ME == 32:
|
||||
return "insrwi" + suffix, "r%i, r%i, %i, %i" %(A, S, 32 - MB - SH, MB)
|
||||
return "rlwimi" + suffix, "r%i, r%i, %i, %i, %i" %(A, S, SH, MB, ME)
|
||||
|
||||
def rlwinm(value, addr):
|
||||
S, A, SH, MB, ME, Rc = decodeR(value)
|
||||
suffix = "." * Rc
|
||||
if MB == 0 and ME == 31 - SH:
|
||||
return "slwi" + suffix, "r%i, r%i, %i" %(A, S, SH)
|
||||
if ME == 31 and SH == 32 - MB:
|
||||
return "srwi" + suffix, "r%i, r%i, %i" %(A, S, MB)
|
||||
if MB == 0 and ME < 31:
|
||||
return "extlwi" + suffix, "r%i, r%i, %i, %i" %(A, S, ME + 1, SH)
|
||||
if ME == 31 and SH >= 32 - MB:
|
||||
return "extrwi" + suffix, "r%i, r%i, %i, %i" %(A, S, 32 - MB, SH + MB - 32)
|
||||
if MB == 0 and ME == 31:
|
||||
if SH >= 16:
|
||||
return "rotlwi" + suffix, "r%i, r%i, %i" %(A, S, SH)
|
||||
return "rotrwi" + suffix, "r%i, r%i, %i" %(A, S, 32 - SH)
|
||||
if SH == 0 and ME == 31:
|
||||
return "clrlwi" + suffix, "r%i, r%i, %i" %(A, S, MB)
|
||||
if SH == 0 and MB == 0:
|
||||
return "clrrwi" + suffix, "r%i, r%i, %i" %(A, S, 31 - ME)
|
||||
if ME == 31 - SH and MB + SH < 32:
|
||||
return "clrlslwi" + suffix, "r%i, r%i, %i, %i" (MB + SH, SH)
|
||||
return "rlwinm" + suffix, "r%i, r%i, %i, %i, %i" %(A, S, SH, MB, ME)
|
||||
|
||||
def rlwnm(value, addr):
|
||||
S, A, B, MB, ME, Rc = decodeR(value)
|
||||
suffix = "." * Rc
|
||||
if MB == 0 and ME == 31:
|
||||
return "rotlw" + suffix, "r%i, r%i, r%i" %(A, S, B)
|
||||
return "rlwnm" + suffix, "r%i, r%i, r%i, %i, %i" %(A, S, B, MB, ME)
|
||||
|
||||
sc = decode_simple("sc")
|
||||
|
||||
slw = decode_triple_reg("slw", SWAP)
|
||||
sraw = decode_triple_reg("sraw", SWAP)
|
||||
|
||||
def srawi(value, addr):
|
||||
S, A, SH, Rc = decodeX(value)
|
||||
return "srawi" + "." * Rc, "r%i, r%i, %i" %(A, S, SH)
|
||||
|
||||
srw = decode_triple_reg("srw", SWAP)
|
||||
|
||||
stb = decode_memory("stb")
|
||||
stbu = decode_memory("stbu")
|
||||
stbux = decode_memory_indexed("stbux")
|
||||
stbx = decode_memory_indexed("stbx")
|
||||
stfd = decode_memory_float("stfd")
|
||||
stfdu = decode_memory_float("stfdu")
|
||||
stfdux = decode_memory_float_indexed("stfdux")
|
||||
stfdx = decode_memory_float_indexed("stfdx")
|
||||
stfiwx = decode_memory_float_indexed("stfiwx")
|
||||
stfs = decode_memory_float("stfs")
|
||||
stfsu = decode_memory_float("stfsu")
|
||||
stfsux = decode_memory_float_indexed("stfsux")
|
||||
stfsx = decode_memory_float_indexed("stfsx")
|
||||
sth = decode_memory("sth")
|
||||
sthbrx = decode_memory_indexed("sthbrx")
|
||||
sthu = decode_memory("sthu")
|
||||
sthux = decode_memory_indexed("sthux")
|
||||
sthx = decode_memory_indexed("sthx")
|
||||
stmw = decode_memory("stmw")
|
||||
|
||||
def stswi(value, addr):
|
||||
S, A, NB, Rc = decodeX(value)
|
||||
if Rc:
|
||||
return "???"
|
||||
return "stswi", "r%i, r%i, %i" %(S, A, NB)
|
||||
|
||||
stswx = decode_memory_indexed("stswx")
|
||||
stw = decode_memory("stw")
|
||||
stwbrx = decode_memory_indexed("stwbrx")
|
||||
|
||||
def stwcx(value, addr):
|
||||
S, A, B, Rc = decodeX(value)
|
||||
if not Rc:
|
||||
return "???"
|
||||
return "stwcx.", "r%i, r%i, r%i" %(S, A, B)
|
||||
|
||||
stwu = decode_memory("stwu")
|
||||
stwux = decode_memory_indexed("stwux")
|
||||
stwx = decode_memory_indexed("stwx")
|
||||
|
||||
subf = decode_triple_reg("subf", NO_SWAP)
|
||||
subfc = decode_triple_reg("subfc", NO_SWAP)
|
||||
subfe = decode_triple_reg("subfe", NO_SWAP)
|
||||
subfic = decode_double_reg_imm("subfic", SIGNED, NO_SWAP)
|
||||
subfme = decode_double_reg("subfme", NO_SWAP)
|
||||
subfze = decode_double_reg("subfze", NO_SWAP)
|
||||
|
||||
sync = decode_simple("sync")
|
||||
tlbia = decode_simple("tlbia")
|
||||
|
||||
def tlbie(value, addr):
|
||||
D, A, B, Rc = decodeX(value)
|
||||
if D or A or Rc:
|
||||
return "???"
|
||||
return "tlbie", "r%i" %B
|
||||
|
||||
tlbsync = decode_simple("tlbsync")
|
||||
|
||||
def tw(value, addr):
|
||||
TO, A, B, Rc = decodeX(value)
|
||||
if Rc:
|
||||
return "???"
|
||||
|
||||
if TO == 31 and A == 0 and B == 0:
|
||||
return "trap"
|
||||
|
||||
if TO in trap_condition_table:
|
||||
return "tw%s" %trap_condition_table[TO], "r%i, r%i" %(A, B)
|
||||
return "tw", "%i, r%i, r%i" %(TO, A, B)
|
||||
|
||||
def twi(value, addr):
|
||||
TO, A, SIMM = decodeD(value)
|
||||
SIMM = extend_sign(SIMM)
|
||||
|
||||
if TO in trap_condition_table:
|
||||
return "tw%si" %trap_condition_table[TO], "r%i, %s" %(A, ihex(SIMM))
|
||||
return "twi", "%i, r%i, %s" %(TO, A, ihex(SIMM))
|
||||
|
||||
xor = decode_triple_reg("xor", SWAP)
|
||||
xori = decode_double_reg_imm("xori", UNSIGNED, SWAP)
|
||||
xoris = decode_double_reg_imm("xoris", UNSIGNED, SWAP)
|
||||
|
||||
|
||||
opcode_table_19 = {
|
||||
0: mcrf,
|
||||
16: bclr,
|
||||
33: crnor,
|
||||
50: rfi,
|
||||
129: crandc,
|
||||
150: isync,
|
||||
193: crxor,
|
||||
225: crnand,
|
||||
257: crand,
|
||||
289: creqv,
|
||||
417: crorc,
|
||||
449: cror,
|
||||
528: bcctr
|
||||
}
|
||||
|
||||
opcode_table_31 = {
|
||||
0: cmp,
|
||||
4: tw,
|
||||
8: subfc,
|
||||
10: addc,
|
||||
11: mulhwu,
|
||||
19: mfcr,
|
||||
20: lwarx,
|
||||
23: lwzx,
|
||||
24: slw,
|
||||
26: cntlzw,
|
||||
28: and_,
|
||||
32: cmpl,
|
||||
40: subf,
|
||||
54: dcbst,
|
||||
55: lwzux,
|
||||
60: andc,
|
||||
75: mulhw,
|
||||
83: mfmsr,
|
||||
86: dcbf,
|
||||
87: lbzx,
|
||||
119: lbzux,
|
||||
124: nor,
|
||||
138: adde,
|
||||
146: mtmsr,
|
||||
150: stwcx,
|
||||
151: stwx,
|
||||
183: stwux,
|
||||
202: addze,
|
||||
210: mtsr,
|
||||
215: stbx,
|
||||
234: addme,
|
||||
242: mtsrin,
|
||||
246: dcbtst,
|
||||
247: stbux,
|
||||
266: add,
|
||||
278: dcbt,
|
||||
279: lhzx,
|
||||
284: eqv,
|
||||
306: tlbie,
|
||||
311: lhzux,
|
||||
316: xor,
|
||||
339: mfspr,
|
||||
343: lhax,
|
||||
370: tlbia,
|
||||
375: lhaux,
|
||||
407: sthx,
|
||||
412: orc,
|
||||
439: sthux,
|
||||
444: or_,
|
||||
467: mtspr,
|
||||
470: dcbi,
|
||||
476: nand,
|
||||
512: mcrxr,
|
||||
533: lswx,
|
||||
534: lwbrx,
|
||||
535: lfsx,
|
||||
536: srw,
|
||||
566: tlbsync,
|
||||
567: lfsux,
|
||||
595: mfsr,
|
||||
597: lswi,
|
||||
598: sync,
|
||||
599: lfdx,
|
||||
631: lfdux,
|
||||
659: mfsrin,
|
||||
661: stswx,
|
||||
662: stwbrx,
|
||||
663: stfsx,
|
||||
695: stfsux,
|
||||
725: stswi,
|
||||
727: stfdx,
|
||||
758: dcba,
|
||||
759: stfdux,
|
||||
790: lhbrx,
|
||||
792: sraw,
|
||||
824: srawi,
|
||||
854: eieio,
|
||||
918: sthbrx,
|
||||
922: extsh,
|
||||
954: extsb,
|
||||
982: icbi,
|
||||
983: stfiwx,
|
||||
1014: dcbz
|
||||
}
|
||||
|
||||
opcode_table_59 = {
|
||||
18: fdivs,
|
||||
20: fsubs,
|
||||
21: fadds,
|
||||
22: fsqrts,
|
||||
24: fres,
|
||||
25: fmuls,
|
||||
28: fmsubs,
|
||||
29: fmadds,
|
||||
30: fnmsubs,
|
||||
31: fnmadds
|
||||
}
|
||||
|
||||
opcode_table_63 = {
|
||||
0: fcmpu,
|
||||
12: frsp,
|
||||
14: fctiw,
|
||||
15: fctiwz,
|
||||
18: fdiv,
|
||||
20: fsub,
|
||||
21: fadd,
|
||||
22: fsqrt,
|
||||
23: fsel,
|
||||
25: fmul,
|
||||
26: fsqrte,
|
||||
28: fmsub,
|
||||
29: fmadd,
|
||||
30: fnmsub,
|
||||
31: fnmadd,
|
||||
32: fcmpo,
|
||||
38: mtfsb1,
|
||||
40: fneg,
|
||||
64: mcrfs,
|
||||
70: mtfsb0,
|
||||
72: fmr,
|
||||
134: mtfsfi,
|
||||
136: fnabs,
|
||||
264: fabs,
|
||||
583: mffs,
|
||||
711: mtfsf
|
||||
}
|
||||
|
||||
def opcode19(value, addr):
|
||||
XO = (value >> 1) & 0x3FF
|
||||
if XO not in opcode_table_19:
|
||||
return "???"
|
||||
return opcode_table_19[XO](value, addr)
|
||||
|
||||
def opcode31(value, addr):
|
||||
XO = (value >> 1) & 0x3FF
|
||||
if XO not in opcode_table_31:
|
||||
return "???"
|
||||
return opcode_table_31[XO](value, addr)
|
||||
|
||||
def opcode59(value, addr):
|
||||
XO = (value >> 1) & 0x1F
|
||||
if XO not in opcode_table_59:
|
||||
return "???"
|
||||
return opcode_table_59[XO](value, addr)
|
||||
|
||||
def opcode63(value, addr):
|
||||
XO = (value >> 1) & 0x3FF
|
||||
if XO not in opcode_table_63:
|
||||
return "???"
|
||||
return opcode_table_63[XO](value, addr)
|
||||
|
||||
|
||||
opcode_table = {
|
||||
3: twi,
|
||||
7: mulli,
|
||||
8: subfic,
|
||||
10: cmpli,
|
||||
11: cmpi,
|
||||
12: addic,
|
||||
13: addic_,
|
||||
14: addi,
|
||||
15: addis,
|
||||
16: bc,
|
||||
17: sc,
|
||||
18: b,
|
||||
19: opcode19,
|
||||
20: rlwimi,
|
||||
21: rlwinm,
|
||||
23: rlwnm,
|
||||
24: ori,
|
||||
25: oris,
|
||||
26: xori,
|
||||
27: xoris,
|
||||
28: andi,
|
||||
29: andis,
|
||||
31: opcode31,
|
||||
32: lwz,
|
||||
33: lwzu,
|
||||
34: lbz,
|
||||
35: lbzu,
|
||||
36: stw,
|
||||
37: stwu,
|
||||
38: stb,
|
||||
39: stbu,
|
||||
40: lhz,
|
||||
41: lhzu,
|
||||
42: lha,
|
||||
43: lhau,
|
||||
44: sth,
|
||||
45: sthu,
|
||||
46: lmw,
|
||||
47: stmw,
|
||||
48: lfs,
|
||||
49: lfsu,
|
||||
50: lfd,
|
||||
51: lfdu,
|
||||
52: stfs,
|
||||
53: stfsu,
|
||||
54: stfd,
|
||||
55: stfdu,
|
||||
59: opcode59,
|
||||
63: opcode63
|
||||
}
|
||||
|
||||
def disassemble(value, address):
|
||||
opcode = value >> 26
|
||||
if opcode not in opcode_table:
|
||||
return "???"
|
||||
instr = opcode_table[opcode](value, address)
|
||||
if type(instr) == str:
|
||||
return instr
|
||||
return "%-10s%s" %(instr[0], instr[1])
|
248
src/cafe/coreinit.cpp
Normal file
248
src/cafe/coreinit.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "hbl.h"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
int (*OSDynLoad_Acquire)(const char *name, uint32_t *handle);
|
||||
int (*OSDynLoad_FindExport)(uint32_t handle, bool isData, const char *name, void *ptr);
|
||||
int (*OSDynLoad_GetModuleName)(uint32_t handle, char *name, int *size);
|
||||
OSMutex *OSDynLoad_gLoaderLock;
|
||||
|
||||
bool (*OSIsDebuggerInitialized)();
|
||||
|
||||
void (*exit)(int result);
|
||||
void (*_Exit)(int result);
|
||||
|
||||
void (*OSFatal)(const char *msg);
|
||||
|
||||
uint32_t (*OSGetSymbolName)(uint32_t addr, char *buffer, size_t bufsize);
|
||||
void (*DisassemblePPCRange)(uint32_t start, uint32_t end, DisassemblyPrintFn printFunc, DisassemblyFindSymbolFn symFunc, DisassemblyFlags flags);
|
||||
void (*DisassemblePPCOpcode)(uint32_t addr, void *buffer, size_t bufsize, DisassemblyFindSymbolFn symFunc, DisassemblyFlags flags);
|
||||
|
||||
int (*OSSetExceptionCallback)(OSExceptionType type, OSExceptionCallback callback);
|
||||
int (*OSSetExceptionCallbackEx)(OSExceptionMode mode, OSExceptionType type, OSExceptionCallback callback);
|
||||
void (*OSLoadContext)(OSContext *context);
|
||||
|
||||
int (*OSDisableInterrupts)();
|
||||
void (*OSRestoreInterrupts)(int state);
|
||||
|
||||
void (*__OSLockScheduler)(void *);
|
||||
void (*__OSUnlockScheduler)(void *);
|
||||
|
||||
void (*OSInitMutex)(OSMutex *mutex);
|
||||
void (*OSLockMutex)(OSMutex *mutex);
|
||||
void (*OSUnlockMutex)(OSMutex *mutex);
|
||||
|
||||
void (*OSInitMessageQueue)(OSMessageQueue *queue, OSMessage *messages, int count);
|
||||
bool (*OSSendMessage)(OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags);
|
||||
bool (*OSReceiveMessage)(OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags);
|
||||
|
||||
void (*OSCreateAlarm)(OSAlarm *alarm);
|
||||
bool (*OSSetAlarm)(OSAlarm *alarm, uint64_t timeout, OSAlarmCallback callback);
|
||||
void (*OSCancelAlarm)(OSAlarm *alarm);
|
||||
bool (*OSWaitAlarm)(OSAlarm *alarm);
|
||||
|
||||
OSThread *(*OSGetCurrentThread)();
|
||||
OSThread *(*OSGetDefaultThread)(int core);
|
||||
bool (*OSCreateThread)(OSThread *thread, OSThreadFunc func, int argc, void *argv, void *stack, uint32_t stackSize, int priority, int attr);
|
||||
int (*OSResumeThread)(OSThread *thread);
|
||||
bool (*OSJoinThread)(OSThread *thread, int *result);
|
||||
void (*OSExitThread)(int result);
|
||||
const char *(*OSGetThreadName)(OSThread *thread);
|
||||
void (*OSSetThreadName)(OSThread *thread, const char *name);
|
||||
uint32_t (*OSGetThreadAffinity)(OSThread *thread);
|
||||
int (*OSGetThreadPriority)(OSThread *thread);
|
||||
|
||||
OSSystemInfo *(*OSGetSystemInfo)();
|
||||
void (*OSSleepTicks)(uint64_t ticks);
|
||||
|
||||
uint64_t (*OSGetTitleID)();
|
||||
|
||||
int (*OSGetMemBound)(OSMemoryType type, uint32_t *startPtr, uint32_t *sizePtr);
|
||||
uint32_t (*OSEffectiveToPhysical)(uint32_t addr);
|
||||
|
||||
void (*OSScreenInit)();
|
||||
uint32_t (*OSScreenGetBufferSizeEx)(int screen);
|
||||
void (*OSScreenSetBufferEx)(int screen, void *buffer);
|
||||
void (*OSScreenEnableEx)(int screen, bool enabled);
|
||||
void (*OSScreenClearBufferEx)(int screen, uint32_t color);
|
||||
void (*OSScreenFlipBuffersEx)(int screen);
|
||||
void (*OSScreenPutPixelEx)(int screen, int x, int y, uint32_t color);
|
||||
void (*OSScreenPutFontEx)(int screen, int x, int y, const char *text);
|
||||
|
||||
void (*DCFlushRange)(const void *buffer, uint32_t length);
|
||||
void (*DCInvalidateRange)(const void *buffer, uint32_t length);
|
||||
void (*ICInvalidateRange)(const void *buffer, uint32_t length);
|
||||
|
||||
int (*IOS_Open)(const char *path, int mode);
|
||||
int (*IOS_Ioctl)(int fd, uint32_t request, const void *inptr, uint32_t inlen, void *outptr, uint32_t outlen);
|
||||
int (*IOS_Close)(int fd);
|
||||
|
||||
int (*FSInit)();
|
||||
int (*FSAddClient)(FSClient *client, uint32_t flags);
|
||||
int (*FSInitCmdBlock)(FSCmdBlock *block);
|
||||
int (*FSGetMountSource)(FSClient *client, FSCmdBlock *block, FSMountSourceType type, FSMountSource *source, uint32_t flags);
|
||||
int (*FSMount)(FSClient *client, FSCmdBlock *block, FSMountSource *source, char *path, uint32_t bytes, uint32_t flags);
|
||||
int (*FSMakeDir)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
int (*FSChangeDir)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
int (*FSGetCwd)(FSClient *client, FSCmdBlock *block, char *path, int length, uint32_t flags);
|
||||
int (*FSOpenDir)(FSClient *client, FSCmdBlock *block, const char *path, int *handle, uint32_t flags);
|
||||
int (*FSReadDir)(FSClient *client, FSCmdBlock *block, int handle, FSDirectoryEntry *entry, uint32_t flags);
|
||||
int (*FSCloseDir)(FSClient *client, FSCmdBlock *block, int handle, uint32_t flags);
|
||||
int (*FSOpenFile)(FSClient *client, FSCmdBlock *block, const char *path, const char *mode, int *handle, uint32_t flags);
|
||||
int (*FSGetStatFile)(FSClient *client, FSCmdBlock *block, int handle, FSStat *stat, uint32_t flags);
|
||||
int (*FSReadFile)(FSClient *client, FSCmdBlock *block, void *buffer, int size, int count, int handle, int flag, uint32_t flags);
|
||||
int (*FSWriteFile)(FSClient *client, FSCmdBlock *block, const void *buffer, int size, int count, int handle, int flag, uint32_t flags);
|
||||
int (*FSCloseFile)(FSClient *client, FSCmdBlock *block, int handle, uint32_t flags);
|
||||
int (*FSGetStat)(FSClient *client, FSCmdBlock *block, const char *path, FSStat *stat, uint32_t flags);
|
||||
int (*FSRename)(FSClient *client, FSCmdBlock *block, const char *oldPath, const char *newPath, uint32_t flags);
|
||||
int (*FSRemove)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
int (*FSDelClient)(FSClient *client, uint32_t flags);
|
||||
void (*FSShutdown)();
|
||||
|
||||
int (*MCP_Open)();
|
||||
int (*MCP_GetDeviceId)(int handle, uint32_t *deviceId);
|
||||
int (*MCP_TitleList)(int handle, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
int (*MCP_TitleListByAppType)(int handle, uint32_t appType, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
int (*MCP_TitleListByDevice)(int handle, const char *device, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
void (*MCP_Close)(int handle);
|
||||
|
||||
void (*__KernelGetInfo)(KernelInfoType type, void *buffer, uint32_t size, uint32_t unk);
|
||||
|
||||
int (*snprintf)(char *str, size_t size, const char *format, ...);
|
||||
|
||||
void *(*MEMGetBaseHeapHandle)(int type);
|
||||
uint32_t (*MEMGetAllocatableSizeForExpHeapEx)(void *handle, int alignment);
|
||||
|
||||
void *(**pMEMAllocFromDefaultHeap)(uint32_t size);
|
||||
void *(**pMEMAllocFromDefaultHeapEx)(uint32_t size, int alignment);
|
||||
void (**pMEMFreeToDefaultHeap)(void *ptr);
|
||||
|
||||
OSDynLoad_RPLInfo **pMainRPL;
|
||||
OSDynLoad_RPLInfo **pFirstRPL;
|
||||
OSThread **pThreadList;
|
||||
|
||||
void coreinitInitialize() {
|
||||
*(uint32_t *)&OSDynLoad_Acquire = OS_SPECIFICS->OSDynLoad_Acquire;
|
||||
*(uint32_t *)&OSDynLoad_FindExport = OS_SPECIFICS->OSDynLoad_FindExport;
|
||||
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("coreinit.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSDynLoad_GetModuleName", &OSDynLoad_GetModuleName);
|
||||
OSDynLoad_FindExport(handle, true, "OSDynLoad_gLoaderLock", &OSDynLoad_gLoaderLock);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSIsDebuggerInitialized", &OSIsDebuggerInitialized);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "exit", &exit);
|
||||
OSDynLoad_FindExport(handle, false, "_Exit", &_Exit);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSFatal", &OSFatal);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSGetSymbolName", &OSGetSymbolName);
|
||||
OSDynLoad_FindExport(handle, false, "DisassemblePPCRange", &DisassemblePPCRange);
|
||||
OSDynLoad_FindExport(handle, false, "DisassemblePPCOpcode", &DisassemblePPCOpcode);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSSetExceptionCallback", &OSSetExceptionCallback);
|
||||
OSDynLoad_FindExport(handle, false, "OSSetExceptionCallbackEx", &OSSetExceptionCallbackEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSLoadContext", &OSLoadContext);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSDisableInterrupts", &OSDisableInterrupts);
|
||||
OSDynLoad_FindExport(handle, false, "OSRestoreInterrupts", &OSRestoreInterrupts);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "__OSLockScheduler", &__OSLockScheduler);
|
||||
OSDynLoad_FindExport(handle, false, "__OSUnlockScheduler", &__OSUnlockScheduler);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSInitMutex", &OSInitMutex);
|
||||
OSDynLoad_FindExport(handle, false, "OSLockMutex", &OSLockMutex);
|
||||
OSDynLoad_FindExport(handle, false, "OSUnlockMutex", &OSUnlockMutex);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSInitMessageQueue", &OSInitMessageQueue);
|
||||
OSDynLoad_FindExport(handle, false, "OSSendMessage", &OSSendMessage);
|
||||
OSDynLoad_FindExport(handle, false, "OSReceiveMessage", &OSReceiveMessage);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSCreateAlarm", &OSCreateAlarm);
|
||||
OSDynLoad_FindExport(handle, false, "OSSetAlarm", &OSSetAlarm);
|
||||
OSDynLoad_FindExport(handle, false, "OSCancelAlarm", &OSCancelAlarm);
|
||||
OSDynLoad_FindExport(handle, false, "OSWaitAlarm", &OSWaitAlarm);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSGetCurrentThread", &OSGetCurrentThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSGetDefaultThread", &OSGetDefaultThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSCreateThread", &OSCreateThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSResumeThread", &OSResumeThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSJoinThread", &OSJoinThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSExitThread", &OSExitThread);
|
||||
OSDynLoad_FindExport(handle, false, "OSGetThreadName", &OSGetThreadName);
|
||||
OSDynLoad_FindExport(handle, false, "OSSetThreadName", &OSSetThreadName);
|
||||
OSDynLoad_FindExport(handle, false, "OSGetThreadAffinity", &OSGetThreadAffinity);
|
||||
OSDynLoad_FindExport(handle, false, "OSGetThreadPriority", &OSGetThreadPriority);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSGetSystemInfo", &OSGetSystemInfo);
|
||||
OSDynLoad_FindExport(handle, false, "OSSleepTicks", &OSSleepTicks);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSGetTitleID", &OSGetTitleID);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSGetMemBound", &OSGetMemBound);
|
||||
OSDynLoad_FindExport(handle, false, "OSEffectiveToPhysical", &OSEffectiveToPhysical);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenInit", &OSScreenInit);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenSetBufferEx", &OSScreenSetBufferEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenEnableEx", &OSScreenEnableEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenClearBufferEx", &OSScreenClearBufferEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenPutPixelEx", &OSScreenPutPixelEx);
|
||||
OSDynLoad_FindExport(handle, false, "OSScreenPutFontEx", &OSScreenPutFontEx);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "DCFlushRange", &DCFlushRange);
|
||||
OSDynLoad_FindExport(handle, false, "DCInvalidateRange", &DCInvalidateRange);
|
||||
OSDynLoad_FindExport(handle, false, "ICInvalidateRange", &ICInvalidateRange);
|
||||
OSDynLoad_FindExport(handle, false, "IOS_Open", &IOS_Open);
|
||||
OSDynLoad_FindExport(handle, false, "IOS_Ioctl", &IOS_Ioctl);
|
||||
OSDynLoad_FindExport(handle, false, "IOS_Close", &IOS_Close);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "FSInit", &FSInit);
|
||||
OSDynLoad_FindExport(handle, false, "FSAddClient", &FSAddClient);
|
||||
OSDynLoad_FindExport(handle, false, "FSInitCmdBlock", &FSInitCmdBlock);
|
||||
OSDynLoad_FindExport(handle, false, "FSGetMountSource", &FSGetMountSource);
|
||||
OSDynLoad_FindExport(handle, false, "FSMount", &FSMount);
|
||||
OSDynLoad_FindExport(handle, false, "FSMakeDir", &FSMakeDir);
|
||||
OSDynLoad_FindExport(handle, false, "FSChangeDir", &FSChangeDir);
|
||||
OSDynLoad_FindExport(handle, false, "FSGetCwd", &FSGetCwd);
|
||||
OSDynLoad_FindExport(handle, false, "FSOpenDir", &FSOpenDir);
|
||||
OSDynLoad_FindExport(handle, false, "FSReadDir", &FSReadDir);
|
||||
OSDynLoad_FindExport(handle, false, "FSCloseDir", &FSCloseDir);
|
||||
OSDynLoad_FindExport(handle, false, "FSOpenFile", &FSOpenFile);
|
||||
OSDynLoad_FindExport(handle, false, "FSGetStatFile", &FSGetStatFile);
|
||||
OSDynLoad_FindExport(handle, false, "FSReadFile", &FSReadFile);
|
||||
OSDynLoad_FindExport(handle, false, "FSWriteFile", &FSWriteFile);
|
||||
OSDynLoad_FindExport(handle, false, "FSCloseFile", &FSCloseFile);
|
||||
OSDynLoad_FindExport(handle, false, "FSGetStat", &FSGetStat);
|
||||
OSDynLoad_FindExport(handle, false, "FSRename", &FSRename);
|
||||
OSDynLoad_FindExport(handle, false, "FSRemove", &FSRemove);
|
||||
OSDynLoad_FindExport(handle, false, "FSDelClient", &FSDelClient);
|
||||
OSDynLoad_FindExport(handle, false, "FSShutdown", &FSShutdown);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "MCP_Open", &MCP_Open);
|
||||
OSDynLoad_FindExport(handle, false, "MCP_GetDeviceId", &MCP_GetDeviceId);
|
||||
OSDynLoad_FindExport(handle, false, "MCP_TitleList", &MCP_TitleList);
|
||||
OSDynLoad_FindExport(handle, false, "MCP_TitleListByAppType", &MCP_TitleListByAppType);
|
||||
OSDynLoad_FindExport(handle, false, "MCP_TitleListByDevice", &MCP_TitleListByDevice);
|
||||
OSDynLoad_FindExport(handle, false, "MCP_Close", &MCP_Close);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "__KernelGetInfo", &__KernelGetInfo);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "__os_snprintf", &snprintf);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "MEMGetBaseHeapHandle", &MEMGetBaseHeapHandle);
|
||||
OSDynLoad_FindExport(handle, false, "MEMGetAllocatableSizeForExpHeapEx", &MEMGetAllocatableSizeForExpHeapEx);
|
||||
|
||||
OSDynLoad_FindExport(handle, true, "MEMAllocFromDefaultHeap", &pMEMAllocFromDefaultHeap);
|
||||
OSDynLoad_FindExport(handle, true, "MEMAllocFromDefaultHeapEx", &pMEMAllocFromDefaultHeapEx);
|
||||
OSDynLoad_FindExport(handle, true, "MEMFreeToDefaultHeap", &pMEMFreeToDefaultHeap);
|
||||
|
||||
pMainRPL = (OSDynLoad_RPLInfo **)0x10081014;
|
||||
pFirstRPL = (OSDynLoad_RPLInfo **)0x10081018;
|
||||
pThreadList = (OSThread **)0x100567F8;
|
||||
}
|
513
src/cafe/coreinit.h
Normal file
513
src/cafe/coreinit.h
Normal file
@ -0,0 +1,513 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
// Timers
|
||||
#define OSTimerClockSpeed ((OSGetSystemInfo()->busClockSpeed) / 4)
|
||||
|
||||
#define OSSecondsToTicks(val) ((uint64_t)(val) * (uint64_t)OSTimerClockSpeed)
|
||||
#define OSMillisecondsToTicks(val) (((uint64_t)(val) * (uint64_t)OSTimerClockSpeed) / 1000ull)
|
||||
|
||||
#define OSTicksToSeconds(val) ((uint64_t)(val) / (uint64_t)OSTimerClockSpeed)
|
||||
#define OSTicksToMilliseconds(val) (((uint64_t)(val) * 1000ull) / (uint64_t)OSTimerClockSpeed)
|
||||
|
||||
// Memory
|
||||
enum OSMemoryType {
|
||||
MEM1 = 1,
|
||||
MEM2 = 2
|
||||
};
|
||||
|
||||
// System
|
||||
enum KernelInfoType {
|
||||
TITLE_INFO = 0,
|
||||
SYSTEM_INFO = 1,
|
||||
PLATFORM_INFO = 2,
|
||||
|
||||
KERNEL_STATISTICS = 4,
|
||||
PERFORMANCE_NUMBERS = 5,
|
||||
|
||||
PROCESS_INFO = 8,
|
||||
|
||||
CRASH_INFO = 11,
|
||||
APP_CRASH_CONTROL = 12,
|
||||
COS_REPORT_MASKS = 13,
|
||||
CRASH_RECOVERY = 14,
|
||||
CRASH_DETAIL_LEVEL = 15,
|
||||
CRASH_DUMP_TYPE = 16,
|
||||
SHUTDOWN_REASON = 17,
|
||||
WRITE_GATHER_REGS = 18,
|
||||
PROC_DATA_BOUNDS = 19
|
||||
};
|
||||
|
||||
struct OSSystemInfo {
|
||||
uint32_t busClockSpeed;
|
||||
uint32_t coreClockSpeed;
|
||||
int64_t baseTime;
|
||||
char _10[0x10];
|
||||
};
|
||||
|
||||
struct OSTitleInfo {
|
||||
char _0[0xC];
|
||||
uint32_t ramStart;
|
||||
uint32_t ramEnd;
|
||||
char _14[0x20];
|
||||
uint32_t systemHeapSize;
|
||||
char _38[0x40];
|
||||
uint32_t textStart;
|
||||
uint32_t _7C;
|
||||
uint32_t textSize;
|
||||
uint32_t dataStart;
|
||||
uint32_t _88;
|
||||
uint32_t dataSize;
|
||||
uint32_t loadStart;
|
||||
uint32_t _94;
|
||||
uint32_t loadSize;
|
||||
char _9C[0xC];
|
||||
};
|
||||
|
||||
struct OSTitleInfoEx {
|
||||
OSTitleInfo info;
|
||||
uint64_t osVersionId;
|
||||
};
|
||||
|
||||
// OSDynLoad
|
||||
struct OSDynLoad_NotifyData {
|
||||
const char *path;
|
||||
uint32_t textAddr;
|
||||
uint32_t textOffset;
|
||||
uint32_t textSize;
|
||||
uint32_t dataAddr;
|
||||
uint32_t dataOffset;
|
||||
uint32_t dataSize;
|
||||
uint32_t readAddr;
|
||||
uint32_t readOffset;
|
||||
uint32_t readSize;
|
||||
};
|
||||
|
||||
struct OSDynLoad_RPLInfo {
|
||||
uint32_t handle;
|
||||
uint32_t _4;
|
||||
const char *name;
|
||||
char _C[0x1C];
|
||||
OSDynLoad_NotifyData *notifyData;
|
||||
void *entryPoint;
|
||||
char _30[0x24];
|
||||
OSDynLoad_RPLInfo *next;
|
||||
char _58[0x3C];
|
||||
};
|
||||
|
||||
// Thread / mutex / context
|
||||
struct OSThread;
|
||||
struct OSMutex;
|
||||
struct OSAlarm;
|
||||
|
||||
struct OSContext {
|
||||
uint64_t tag;
|
||||
|
||||
uint32_t gpr[32];
|
||||
|
||||
uint32_t cr;
|
||||
uint32_t lr;
|
||||
uint32_t ctr;
|
||||
uint32_t xer;
|
||||
|
||||
uint32_t srr0;
|
||||
uint32_t srr1;
|
||||
|
||||
uint32_t dsisr;
|
||||
uint32_t dar;
|
||||
|
||||
char _A8[0xC];
|
||||
|
||||
uint32_t fpscr;
|
||||
double fpr[32];
|
||||
|
||||
uint16_t spinLockCount;
|
||||
uint16_t state;
|
||||
|
||||
uint32_t gqr[8];
|
||||
|
||||
uint32_t _1DC;
|
||||
|
||||
double psf[32];
|
||||
|
||||
uint64_t coretime[3];
|
||||
uint64_t starttime;
|
||||
|
||||
uint32_t error;
|
||||
|
||||
uint32_t _304;
|
||||
|
||||
uint32_t pmc1;
|
||||
uint32_t pmc2;
|
||||
uint32_t pmc3;
|
||||
uint32_t pmc4;
|
||||
uint32_t mmcr0;
|
||||
uint32_t mmcr1;
|
||||
};
|
||||
|
||||
struct OSThreadQueue {
|
||||
OSThread *head;
|
||||
OSThread *tail;
|
||||
void *parent;
|
||||
uint32_t _C;
|
||||
};
|
||||
|
||||
struct OSThreadLink {
|
||||
OSThread *next;
|
||||
OSThread *prev;
|
||||
};
|
||||
|
||||
struct OSMutexLink {
|
||||
OSMutex *next;
|
||||
OSMutex *prev;
|
||||
};
|
||||
|
||||
struct OSMutexQueue {
|
||||
OSMutex *head;
|
||||
OSMutex *tail;
|
||||
void *parent;
|
||||
uint32_t _C;
|
||||
};
|
||||
|
||||
struct OSMutex {
|
||||
uint32_t tag;
|
||||
const char *name;
|
||||
uint32_t _8;
|
||||
|
||||
OSThreadQueue queue;
|
||||
OSThread *thread;
|
||||
int count;
|
||||
OSMutexLink link;
|
||||
};
|
||||
|
||||
typedef int (*OSThreadFunc)(int argc, void *argv);
|
||||
|
||||
struct OSThread {
|
||||
OSContext context;
|
||||
|
||||
uint32_t tag;
|
||||
|
||||
uint8_t state;
|
||||
uint8_t attr;
|
||||
uint16_t id;
|
||||
uint32_t suspendCounter;
|
||||
|
||||
int priority;
|
||||
int basePriority;
|
||||
|
||||
int exitValue;
|
||||
|
||||
char _338[0x24];
|
||||
|
||||
OSThreadQueue *queue;
|
||||
OSThreadLink link;
|
||||
|
||||
OSThreadQueue joinQueue;
|
||||
|
||||
OSMutex *mutex;
|
||||
OSMutexQueue mutexQueue;
|
||||
|
||||
OSThreadLink activeLink;
|
||||
|
||||
void *stackBase;
|
||||
void *stackEnd;
|
||||
|
||||
OSThreadFunc entryPoint;
|
||||
|
||||
char _3A0[0x57C - 0x3A0];
|
||||
|
||||
void *specific[0x10];
|
||||
|
||||
int type;
|
||||
|
||||
const char *name;
|
||||
|
||||
char _5C4[0x6A0 - 0x5C4];
|
||||
|
||||
};
|
||||
|
||||
// Messages
|
||||
enum OSMessageFlags {
|
||||
OS_MESSAGE_FLAGS_NONE = 0,
|
||||
OS_MESSAGE_FLAGS_BLOCKING = 1
|
||||
};
|
||||
|
||||
struct OSMessage {
|
||||
uint32_t message;
|
||||
uint32_t args[3];
|
||||
};
|
||||
|
||||
struct OSMessageQueue {
|
||||
uint32_t tag;
|
||||
const char *name;
|
||||
uint32_t _8;
|
||||
OSThreadQueue sendQueue;
|
||||
OSThreadQueue recvQueue;
|
||||
OSMessage *messages;
|
||||
uint32_t size;
|
||||
uint32_t first;
|
||||
uint32_t used;
|
||||
};
|
||||
|
||||
// Alarms
|
||||
struct OSAlarmQueue {
|
||||
uint32_t tag;
|
||||
const char *name;
|
||||
uint32_t _8;
|
||||
|
||||
OSThreadQueue threadQueue;
|
||||
OSAlarm *head;
|
||||
OSAlarm *tail;
|
||||
};
|
||||
|
||||
struct OSAlarmLink {
|
||||
OSAlarm *prev;
|
||||
OSAlarm *next;
|
||||
};
|
||||
|
||||
typedef void (*OSAlarmCallback)(OSAlarm *alarm, OSContext *context);
|
||||
|
||||
struct OSAlarm {
|
||||
uint32_t tag;
|
||||
const char *name;
|
||||
uint32_t _8;
|
||||
OSAlarmCallback callback;
|
||||
uint32_t group;
|
||||
uint32_t _14;
|
||||
uint64_t nextFire;
|
||||
OSAlarmLink link;
|
||||
uint64_t period;
|
||||
uint64_t start;
|
||||
void *userData;
|
||||
uint32_t state;
|
||||
OSThreadQueue threadQueue;
|
||||
OSAlarmQueue *alarmQueue;
|
||||
OSContext *context;
|
||||
};
|
||||
|
||||
// PPC disassembly
|
||||
typedef void (*DisassemblyPrintFn)(const char *fmt, ...);
|
||||
typedef uint32_t (*DisassemblyFindSymbolFn)(uint32_t addr, char *buffer, size_t bufsize);
|
||||
|
||||
enum DisassemblyFlags {
|
||||
DISASSEMBLY_FLAGS_NONE = 0,
|
||||
DISASSEMBLY_FLAGS_SIMPLIFY = 1,
|
||||
DISASSEMBLY_FLAGS_SPACE = 0x20,
|
||||
DISASSEMBLY_FLAGS_PLAIN = 0x40,
|
||||
DISASSEMBLY_FLAGS_NO_OPCODE = 0x80,
|
||||
DISASSEMBLY_FLAGS_PRINT_SYMBOLS = 0x100
|
||||
};
|
||||
|
||||
// Exceptions
|
||||
enum OSExceptionMode {
|
||||
OS_EXCEPTION_MODE_THREAD = 1,
|
||||
OS_EXCEPTION_MODE_GLOBAL = 2,
|
||||
OS_EXCEPTION_MODE_THREAD_ALL_CORES = 3,
|
||||
OS_EXCEPTION_MODE_GLOBAL_ALL_CORES = 4
|
||||
};
|
||||
|
||||
enum OSExceptionType {
|
||||
OS_EXCEPTION_TYPE_DSI = 2,
|
||||
OS_EXCEPTION_TYPE_ISI = 3,
|
||||
OS_EXCEPTION_TYPE_PROGRAM = 6
|
||||
};
|
||||
|
||||
typedef bool (*OSExceptionCallback)(OSContext *context);
|
||||
|
||||
// File system
|
||||
enum FSMode {
|
||||
FS_MODE_READ_OWNER = 0x400,
|
||||
FS_MODE_WRITE_OWNER = 0x200,
|
||||
FS_MODE_EXEC_OWNER = 0x100,
|
||||
|
||||
FS_MODE_READ_GROUP = 0x040,
|
||||
FS_MODE_WRITE_GROUP = 0x020,
|
||||
FS_MODE_EXEC_GROUP = 0x010,
|
||||
|
||||
FS_MODE_READ_OTHER = 0x004,
|
||||
FS_MODE_WRITE_OTHER = 0x002,
|
||||
FS_MODE_EXEC_OTHER = 0x001
|
||||
};
|
||||
|
||||
enum FSStatFlags {
|
||||
FS_STAT_DIRECTORY = 0x80000000
|
||||
};
|
||||
|
||||
enum FSMountSourceType {
|
||||
FS_MOUNT_SOURCE_SD = 0
|
||||
};
|
||||
|
||||
struct FSClient {
|
||||
char data[0x1700];
|
||||
};
|
||||
|
||||
struct FSCmdBlock {
|
||||
char data[0xA80];
|
||||
};
|
||||
|
||||
struct FSMountSource {
|
||||
char data[0x300];
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) FSStat {
|
||||
FSStatFlags flags;
|
||||
FSMode mode;
|
||||
uint32_t owner;
|
||||
uint32_t group;
|
||||
uint32_t size;
|
||||
char _14[0xC];
|
||||
uint32_t entryId;
|
||||
int64_t created;
|
||||
int64_t modified;
|
||||
char _34[0x30];
|
||||
};
|
||||
|
||||
struct FSDirectoryEntry {
|
||||
FSStat info;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
// MCP
|
||||
struct MCPTitleListType {
|
||||
uint64_t titleId;
|
||||
uint32_t _4;
|
||||
char path[56];
|
||||
uint32_t appType;
|
||||
char _48[0xC];
|
||||
uint8_t device;
|
||||
char _55;
|
||||
char indexedDevice[10];
|
||||
uint8_t _60;
|
||||
};
|
||||
|
||||
// Function pointers
|
||||
extern int (*OSDynLoad_Acquire)(const char *name, uint32_t *handle);
|
||||
extern int (*OSDynLoad_FindExport)(uint32_t handle, bool isData, const char *name, void *ptr);
|
||||
extern int (*OSDynLoad_GetModuleName)(uint32_t handle, char *name, int *size);
|
||||
extern OSMutex *OSDynLoad_gLoaderLock;
|
||||
|
||||
extern bool (*OSIsDebuggerInitialized)();
|
||||
|
||||
extern void (*exit)(int result);
|
||||
extern void (*_Exit)(int result);
|
||||
|
||||
extern void (*OSFatal)(const char *msg);
|
||||
|
||||
extern uint32_t (*OSGetSymbolName)(uint32_t addr, char *buffer, size_t bufsize);
|
||||
extern void (*DisassemblePPCRange)(uint32_t start, uint32_t end, DisassemblyPrintFn printFunc, DisassemblyFindSymbolFn symFunc, DisassemblyFlags flags);
|
||||
extern void (*DisassemblePPCOpcode)(uint32_t addr, void *buffer, size_t bufsize, DisassemblyFindSymbolFn symFunc, DisassemblyFlags flags);
|
||||
|
||||
extern int (*OSSetExceptionCallback)(OSExceptionType type, OSExceptionCallback callback);
|
||||
extern int (*OSSetExceptionCallbackEx)(OSExceptionMode mode, OSExceptionType type, OSExceptionCallback callback);
|
||||
extern void (*OSLoadContext)(OSContext *context);
|
||||
|
||||
extern int (*OSDisableInterrupts)();
|
||||
extern void (*OSRestoreInterrupts)(int state);
|
||||
|
||||
extern void (*__OSLockScheduler)(void *);
|
||||
extern void (*__OSUnlockScheduler)(void *);
|
||||
|
||||
extern void (*OSInitMutex)(OSMutex *mutex);
|
||||
extern void (*OSLockMutex)(OSMutex *mutex);
|
||||
extern void (*OSUnlockMutex)(OSMutex *mutex);
|
||||
|
||||
extern void (*OSInitMessageQueue)(OSMessageQueue *queue, OSMessage *messages, int count);
|
||||
extern bool (*OSSendMessage)(OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags);
|
||||
extern bool (*OSReceiveMessage)(OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags);
|
||||
|
||||
extern void (*OSCreateAlarm)(OSAlarm *alarm);
|
||||
extern bool (*OSSetAlarm)(OSAlarm *alarm, uint64_t timeout, OSAlarmCallback callback);
|
||||
extern void (*OSCancelAlarm)(OSAlarm *alarm);
|
||||
extern bool (*OSWaitAlarm)(OSAlarm *alarm);
|
||||
|
||||
extern OSThread *(*OSGetCurrentThread)();
|
||||
extern OSThread *(*OSGetDefaultThread)(int core);
|
||||
extern bool (*OSCreateThread)(OSThread *thread, OSThreadFunc func, int argc, void *argv, void *stack, uint32_t stackSize, int priority, int attr);
|
||||
extern int (*OSResumeThread)(OSThread *thread);
|
||||
extern bool (*OSJoinThread)(OSThread *thread, int *result);
|
||||
extern void (*OSExitThread)(int result);
|
||||
extern const char *(*OSGetThreadName)(OSThread *thread);
|
||||
extern void (*OSSetThreadName)(OSThread *thread, const char *name);
|
||||
extern uint32_t (*OSGetThreadAffinity)(OSThread *thread);
|
||||
extern int (*OSGetThreadPriority)(OSThread *thread);
|
||||
|
||||
extern OSSystemInfo *(*OSGetSystemInfo)();
|
||||
extern void (*OSSleepTicks)(uint64_t ticks);
|
||||
|
||||
extern uint64_t (*OSGetTitleID)();
|
||||
|
||||
extern int (*OSGetMemBound)(OSMemoryType type, uint32_t *startPtr, uint32_t *sizePtr);
|
||||
extern uint32_t (*OSEffectiveToPhysical)(uint32_t addr);
|
||||
|
||||
extern void (*OSScreenInit)();
|
||||
extern uint32_t (*OSScreenGetBufferSizeEx)(int screen);
|
||||
extern void (*OSScreenSetBufferEx)(int screen, void *buffer);
|
||||
extern void (*OSScreenEnableEx)(int screen, bool enabled);
|
||||
extern void (*OSScreenClearBufferEx)(int screen, uint32_t color);
|
||||
extern void (*OSScreenFlipBuffersEx)(int screen);
|
||||
extern void (*OSScreenPutPixelEx)(int screen, int x, int y, uint32_t color);
|
||||
extern void (*OSScreenPutFontEx)(int screen, int x, int y, const char *text);
|
||||
|
||||
extern void (*DCFlushRange)(const void *buffer, uint32_t length);
|
||||
extern void (*DCInvalidateRange)(const void *buffer, uint32_t length);
|
||||
extern void (*ICInvalidateRange)(const void *buffer, uint32_t length);
|
||||
|
||||
extern int (*IOS_Open)(const char *path, int mode);
|
||||
extern int (*IOS_Ioctl)(int fd, uint32_t request, const void *inptr, uint32_t inlen, void *outptr, uint32_t outlen);
|
||||
extern int (*IOS_Close)(int fd);
|
||||
|
||||
extern int (*FSInit)();
|
||||
extern int (*FSAddClient)(FSClient *client, uint32_t flags);
|
||||
extern int (*FSInitCmdBlock)(FSCmdBlock *block);
|
||||
extern int (*FSGetMountSource)(FSClient *client, FSCmdBlock *block, FSMountSourceType type, FSMountSource *source, uint32_t flags);
|
||||
extern int (*FSMount)(FSClient *client, FSCmdBlock *block, FSMountSource *source, char *path, uint32_t bytes, uint32_t flags);
|
||||
extern int (*FSMakeDir)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
extern int (*FSChangeDir)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
extern int (*FSGetCwd)(FSClient *client, FSCmdBlock *block, char *path, int length, uint32_t flags);
|
||||
extern int (*FSOpenDir)(FSClient *client, FSCmdBlock *block, const char *path, int *handle, uint32_t flags);
|
||||
extern int (*FSReadDir)(FSClient *client, FSCmdBlock *block, int handle, FSDirectoryEntry *entry, uint32_t flags);
|
||||
extern int (*FSCloseDir)(FSClient *client, FSCmdBlock *block, int handle, uint32_t flags);
|
||||
extern int (*FSOpenFile)(FSClient *client, FSCmdBlock *block, const char *path, const char *mode, int *handle, uint32_t flags);
|
||||
extern int (*FSGetStatFile)(FSClient *client, FSCmdBlock *block, int handle, FSStat *stat, uint32_t flags);
|
||||
extern int (*FSReadFile)(FSClient *client, FSCmdBlock *block, void *buffer, int size, int count, int handle, int flag, uint32_t flags);
|
||||
extern int (*FSWriteFile)(FSClient *client, FSCmdBlock *block, const void *buffer, int size, int count, int handle, int flag, uint32_t flags);
|
||||
extern int (*FSCloseFile)(FSClient *client, FSCmdBlock *block, int handle, uint32_t flags);
|
||||
extern int (*FSGetStat)(FSClient *client, FSCmdBlock *block, const char *path, FSStat *stat, uint32_t flags);
|
||||
extern int (*FSRename)(FSClient *client, FSCmdBlock *block, const char *oldPath, const char *newPath, uint32_t flags);
|
||||
extern int (*FSRemove)(FSClient *client, FSCmdBlock *block, const char *path, uint32_t flags);
|
||||
extern int (*FSDelClient)(FSClient *client, uint32_t flags);
|
||||
extern void (*FSShutdown)();
|
||||
|
||||
extern int (*MCP_Open)();
|
||||
extern int (*MCP_GetDeviceId)(int handle, uint32_t *deviceId);
|
||||
extern int (*MCP_TitleList)(int handle, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
extern int (*MCP_TitleListByAppType)(int handle, uint32_t appType, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
extern int (*MCP_TitleListByDevice)(int handle, const char *device, uint32_t *count, MCPTitleListType *list, uint32_t size);
|
||||
extern void (*MCP_Close)(int handle);
|
||||
|
||||
extern void (*__KernelGetInfo)(KernelInfoType type, void *buffer, uint32_t size, uint32_t unk);
|
||||
|
||||
extern int (*snprintf)(char *str, size_t size, const char *format, ...);
|
||||
|
||||
extern void *(*MEMGetBaseHeapHandle)(int type);
|
||||
extern uint32_t (*MEMGetAllocatableSizeForExpHeapEx)(void *handle, int alignment);
|
||||
|
||||
extern void *(**pMEMAllocFromDefaultHeap)(uint32_t size);
|
||||
extern void *(**pMEMAllocFromDefaultHeapEx)(uint32_t size, int alignment);
|
||||
extern void (**pMEMFreeToDefaultHeap)(void *ptr);
|
||||
#define MEMAllocFromDefaultHeap (*pMEMAllocFromDefaultHeap)
|
||||
#define MEMAllocFromDefaultHeapEx (*pMEMAllocFromDefaultHeapEx)
|
||||
#define MEMFreeToDefaultHeap (*pMEMFreeToDefaultHeap)
|
||||
|
||||
// Internal
|
||||
extern OSDynLoad_RPLInfo **pMainRPL;
|
||||
extern OSDynLoad_RPLInfo **pFirstRPL;
|
||||
extern OSThread **pThreadList;
|
||||
#define MainRPL (*pMainRPL)
|
||||
#define FirstRPL (*pFirstRPL)
|
||||
#define ThreadList (*pThreadList)
|
||||
|
||||
void coreinitInitialize();
|
20
src/cafe/nn_act.cpp
Normal file
20
src/cafe/nn_act.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace nn::act {
|
||||
uint32_t (*Initialize)();
|
||||
uint8_t (*GetSlotNo)();
|
||||
uint32_t (*GetPersistentIdEx)(uint8_t slot);
|
||||
uint32_t (*Finalize)();
|
||||
}
|
||||
|
||||
void nnactInitialize() {
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("nn_act.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "Initialize__Q2_2nn3actFv", &nn::act::Initialize);
|
||||
OSDynLoad_FindExport(handle, false, "GetSlotNo__Q2_2nn3actFv", &nn::act::GetSlotNo);
|
||||
OSDynLoad_FindExport(handle, false, "GetPersistentIdEx__Q2_2nn3actFUc", &nn::act::GetPersistentIdEx);
|
||||
OSDynLoad_FindExport(handle, false, "Finalize__Q2_2nn3actFv", &nn::act::Finalize);
|
||||
}
|
11
src/cafe/nn_act.h
Normal file
11
src/cafe/nn_act.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace nn::act {
|
||||
extern uint32_t (*Initialize)();
|
||||
extern uint8_t (*GetSlotNo)();
|
||||
extern uint32_t (*GetPersistentIdEx)(uint8_t slot);
|
||||
extern uint32_t (*Finalize)();
|
||||
}
|
||||
|
||||
void nnactInitialize();
|
18
src/cafe/nn_save.cpp
Normal file
18
src/cafe/nn_save.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include <cstdint>
|
||||
|
||||
int (*SAVEInit)();
|
||||
int (*SAVEOpenFile)(FSClient *client, FSCmdBlock *block, uint8_t slot, const char *path, int *handle, uint32_t flags);
|
||||
int (*SAVEGetSharedDataTitlePath)(uint64_t titleId, const char *path, char *outpath, uint32_t outlen);
|
||||
void (*SAVEShutdown)();
|
||||
|
||||
void nnsaveInitialize() {
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("nn_save.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "SAVEInit", &SAVEInit);
|
||||
OSDynLoad_FindExport(handle, false, "SAVEOpenFile", &SAVEOpenFile);
|
||||
OSDynLoad_FindExport(handle, false, "SAVEGetSharedDataTitlePath", &SAVEGetSharedDataTitlePath);
|
||||
OSDynLoad_FindExport(handle, false, "SAVEShutdown", &SAVEShutdown);
|
||||
}
|
12
src/cafe/nn_save.h
Normal file
12
src/cafe/nn_save.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include <cstdint>
|
||||
|
||||
extern int (*SAVEInit)();
|
||||
extern int (*SAVEOpenFile)(FSClient *client, FSCmdBlock *block, uint8_t slot, const char *path, int *handle, uint32_t flags);
|
||||
extern int (*SAVEGetSharedDataTitlePath)(uint64_t titleId, const char *path, char *outpath, uint32_t outlen);
|
||||
extern void (*SAVEShutdown)();
|
||||
|
||||
void nnsaveInitialize();
|
35
src/cafe/nsysnet.cpp
Normal file
35
src/cafe/nsysnet.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#include "cafe/nsysnet.h"
|
||||
#include "cafe/coreinit.h"
|
||||
#include <cstdint>
|
||||
|
||||
int (*socket_lib_init)();
|
||||
int (*inet_aton)(const char *ip, uint32_t *addr);
|
||||
int (*socket)(int domain, int type, int protocol);
|
||||
int (*setsockopt)(int socket, int level, int optname, void *optval, int optlen);
|
||||
int (*connect)(int socket, sockaddr *addr, int addrlen);
|
||||
int (*bind)(int socket, sockaddr *addr, int addrlen);
|
||||
int (*listen)(int socket, int backlog);
|
||||
int (*accept)(int socket, sockaddr *addr, int *addrlen);
|
||||
int (*send)(int socket, const void *buffer, int size, int flags);
|
||||
int (*recv)(int socket, void *buffer, int size, int flags);
|
||||
int (*socketclose)(int socket);
|
||||
int (*socket_lib_finish)();
|
||||
|
||||
void nsysnetInitialize() {
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("nsysnet.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "socket_lib_init", &socket_lib_init);
|
||||
OSDynLoad_FindExport(handle, false, "inet_aton", &inet_aton);
|
||||
OSDynLoad_FindExport(handle, false, "socket", &socket);
|
||||
OSDynLoad_FindExport(handle, false, "setsockopt", &setsockopt);
|
||||
OSDynLoad_FindExport(handle, false, "connect", &connect);
|
||||
OSDynLoad_FindExport(handle, false, "bind", &bind);
|
||||
OSDynLoad_FindExport(handle, false, "listen", &listen);
|
||||
OSDynLoad_FindExport(handle, false, "accept", &accept);
|
||||
OSDynLoad_FindExport(handle, false, "send", &send);
|
||||
OSDynLoad_FindExport(handle, false, "recv", &recv);
|
||||
OSDynLoad_FindExport(handle, false, "socketclose", &socketclose);
|
||||
OSDynLoad_FindExport(handle, false, "socket_lib_finish", &socket_lib_finish);
|
||||
}
|
37
src/cafe/nsysnet.h
Normal file
37
src/cafe/nsysnet.h
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define AF_INET 2
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
#define SOL_SOCKET -1
|
||||
#define SO_REUSEADDR 4
|
||||
|
||||
struct sockaddr {
|
||||
uint16_t family;
|
||||
uint16_t port;
|
||||
uint32_t addr;
|
||||
char zero[8];
|
||||
};
|
||||
|
||||
extern int (*socket_lib_init)();
|
||||
extern int (*inet_aton)(const char *ip, uint32_t *addr);
|
||||
extern int (*socket)(int domain, int type, int protocol);
|
||||
extern int (*setsockopt)(int socket, int level, int optname, void *optval, int optlen);
|
||||
extern int (*connect)(int socket, sockaddr *addr, int addrlen);
|
||||
extern int (*bind)(int socket, sockaddr *addr, int addrlen);
|
||||
extern int (*listen)(int socket, int backlog);
|
||||
extern int (*accept)(int socket, sockaddr *addr, int *addrlen);
|
||||
extern int (*send)(int socket, const void *buffer, int size, int flags);
|
||||
extern int (*recv)(int socket, void *buffer, int size, int flags);
|
||||
extern int (*socketclose)(int socket);
|
||||
extern int (*socket_lib_finish)();
|
||||
|
||||
void nsysnetInitialize();
|
20
src/cafe/sysapp.cpp
Normal file
20
src/cafe/sysapp.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
#include "cafe/sysapp.h"
|
||||
#include "cafe/coreinit.h"
|
||||
|
||||
bool (*SYSCheckTitleExists)(uint64_t titleId);
|
||||
void (*SYSLaunchTitle)(uint64_t titleId);
|
||||
void (*SYSLaunchMenu)();
|
||||
|
||||
void (*SYSLaunchTitleByPathFromLauncher)(const char *path, int len);
|
||||
|
||||
void sysappInitialize() {
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("sysapp.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "SYSCheckTitleExists", &SYSCheckTitleExists);
|
||||
OSDynLoad_FindExport(handle, false, "SYSLaunchTitle", &SYSLaunchTitle);
|
||||
OSDynLoad_FindExport(handle, false, "SYSLaunchMenu", &SYSLaunchMenu);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "_SYSLaunchTitleByPathFromLauncher", &SYSLaunchTitleByPathFromLauncher);
|
||||
}
|
12
src/cafe/sysapp.h
Normal file
12
src/cafe/sysapp.h
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
extern bool (*SYSCheckTitleExists)(uint64_t titleId);
|
||||
extern void (*SYSLaunchTitle)(uint64_t titleId);
|
||||
extern void (*SYSLaunchMenu)();
|
||||
|
||||
extern void (*SYSLaunchTitleByPathFromLauncher)(const char *path, int len);
|
||||
|
||||
void sysappInitialize();
|
12
src/cafe/vpad.cpp
Normal file
12
src/cafe/vpad.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#include "cafe/vpad.h"
|
||||
#include "cafe/coreinit.h"
|
||||
|
||||
void (*VPADRead)(int chan, VPADStatus *buffers, uint32_t count, int *error);
|
||||
|
||||
void vpadInitialize() {
|
||||
uint32_t handle;
|
||||
OSDynLoad_Acquire("vpad.rpl", &handle);
|
||||
|
||||
OSDynLoad_FindExport(handle, false, "VPADRead", &VPADRead);
|
||||
}
|
89
src/cafe/vpad.h
Normal file
89
src/cafe/vpad.h
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum VPADButtons {
|
||||
VPAD_BUTTON_A = 0x8000,
|
||||
VPAD_BUTTON_B = 0x4000,
|
||||
VPAD_BUTTON_X = 0x2000,
|
||||
VPAD_BUTTON_Y = 0x1000,
|
||||
VPAD_BUTTON_LEFT = 0x0800,
|
||||
VPAD_BUTTON_RIGHT = 0x0400,
|
||||
VPAD_BUTTON_UP = 0x0200,
|
||||
VPAD_BUTTON_DOWN = 0x0100,
|
||||
VPAD_BUTTON_ZL = 0x0080,
|
||||
VPAD_BUTTON_ZR = 0x0040,
|
||||
VPAD_BUTTON_L = 0x0020,
|
||||
VPAD_BUTTON_R = 0x0010,
|
||||
VPAD_BUTTON_PLUS = 0x0008,
|
||||
VPAD_BUTTON_MINUS = 0x0004,
|
||||
VPAD_BUTTON_HOME = 0x0002,
|
||||
VPAD_BUTTON_SYNC = 0x0001,
|
||||
|
||||
VPAD_BUTTON_STICK_R = 0x00020000,
|
||||
VPAD_BUTTON_STICK_L = 0x00040000,
|
||||
VPAD_BUTTON_TV = 0x00010000
|
||||
};
|
||||
|
||||
struct VPADVec2D {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct VPADVec3D {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
struct VPADDirection {
|
||||
VPADVec3D x;
|
||||
VPADVec3D y;
|
||||
VPADVec3D z;
|
||||
};
|
||||
|
||||
struct VPADTouchData {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t touched;
|
||||
uint16_t validity;
|
||||
};
|
||||
|
||||
struct VPADAccStatus {
|
||||
VPADVec3D acc;
|
||||
float magnitude;
|
||||
float variation;
|
||||
VPADVec2D vertical;
|
||||
};
|
||||
|
||||
struct VPADStatus {
|
||||
uint32_t hold;
|
||||
uint32_t pressed;
|
||||
uint32_t released;
|
||||
VPADVec2D leftStick;
|
||||
VPADVec2D rightStick;
|
||||
VPADAccStatus accelorometer;
|
||||
VPADVec3D gyro;
|
||||
VPADVec3D angle;
|
||||
uint8_t error;
|
||||
uint8_t _51;
|
||||
|
||||
VPADTouchData tpNormal;
|
||||
VPADTouchData tpFiltered1;
|
||||
VPADTouchData tpFiltered2;
|
||||
uint16_t _6A;
|
||||
|
||||
VPADDirection direction;
|
||||
bool headphones;
|
||||
VPADVec3D mag;
|
||||
uint8_t volume;
|
||||
uint8_t battery;
|
||||
uint8_t micStatus;
|
||||
uint8_t volumeEx;
|
||||
char _A4[8];
|
||||
};
|
||||
|
||||
extern void (*VPADRead)(int chan, VPADStatus *buffers, uint32_t count, int *error);
|
||||
|
||||
void vpadInitialize();
|
15
src/color.h
Normal file
15
src/color.h
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
enum Colors {
|
||||
COLOR_WHITE = 0xFFFFFFFF,
|
||||
COLOR_BLACK = 0x000000FF,
|
||||
|
||||
COLOR_RED = 0xFF0000FF,
|
||||
COLOR_GREEN = 0x00FF00FF,
|
||||
COLOR_BLUE = 0x0000FFFF,
|
||||
|
||||
COLOR_LIGHT_RED = 0xFF8080FF,
|
||||
COLOR_LIGHT_GREEN = 0x80FF80FF,
|
||||
COLOR_LIGHT_BLUE = 0x8080FFFF,
|
||||
};
|
932
src/debugger.cpp
Normal file
932
src/debugger.cpp
Normal file
@ -0,0 +1,932 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "cafe/nsysnet.h"
|
||||
#include "cafe/vpad.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#include "debugger.h"
|
||||
#include "exceptions.h"
|
||||
#include "screen.h"
|
||||
#include "input.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
bool BreakPoint::isRange(uint32_t addr, uint32_t length) {
|
||||
return address >= addr && address <= addr + length - 1;
|
||||
}
|
||||
|
||||
|
||||
BreakPoint *BreakPointMgr::find(uint32_t addr, bool includeSpecial) {
|
||||
BreakPoint *bp = breakpoints.find(addr);
|
||||
if (!bp && includeSpecial) {
|
||||
bp = special.find(addr);
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
||||
BreakPoint *BreakPointMgr::findRange(uint32_t addr, uint32_t length, int *index, bool includeSpecial) {
|
||||
BreakPoint *bp = breakpoints.findRange(addr, length, index);
|
||||
if (bp) {
|
||||
return bp;
|
||||
}
|
||||
|
||||
if (includeSpecial) {
|
||||
int temp = *index - breakpoints.size();
|
||||
bp = special.findRange(addr, length, &temp);
|
||||
*index = temp + breakpoints.size();
|
||||
return bp;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpecialBreakPoint *BreakPointMgr::findSpecial(uint32_t addr, OSThread *thread) {
|
||||
int index = 0;
|
||||
SpecialBreakPoint *bp = special.findRange(addr, 4, &index);
|
||||
while (bp) {
|
||||
if (bp->thread == thread) {
|
||||
return bp;
|
||||
}
|
||||
bp = special.findRange(addr, 4, &index);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool BreakPointMgr::isCustom(uint32_t addr) {
|
||||
return find(addr, false);
|
||||
}
|
||||
|
||||
bool BreakPointMgr::isSpecial(uint32_t addr) {
|
||||
return find(addr, true) && !find(addr, false);
|
||||
}
|
||||
|
||||
bool BreakPointMgr::isSoftware(uint32_t addr) {
|
||||
uint32_t instr = getInstr(addr);
|
||||
uint32_t opcode = instr >> 26;
|
||||
if (opcode == 3) { //twi
|
||||
return true;
|
||||
}
|
||||
else if (opcode == 31) {
|
||||
return (instr & 0x7FF) == 8; //tw
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BreakPointMgr::disable(BreakPoint *bp) {
|
||||
uint32_t address = bp->address;
|
||||
if (bp->address) {
|
||||
bp->address = 0;
|
||||
if (!find(address, true)) {
|
||||
KernelWriteU32(address, bp->instruction);
|
||||
}
|
||||
bp->instruction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPointMgr::enable(BreakPoint *bp, uint32_t addr) {
|
||||
BreakPoint *other = find(addr, true);
|
||||
if (other) {
|
||||
bp->instruction = other->instruction;
|
||||
}
|
||||
else {
|
||||
bp->instruction = *(uint32_t *)addr;
|
||||
KernelWriteU32(addr, TRAP);
|
||||
}
|
||||
bp->address = addr;
|
||||
}
|
||||
|
||||
void BreakPointMgr::init() {
|
||||
OSInitMutex(&mutex);
|
||||
}
|
||||
|
||||
void BreakPointMgr::lock() {
|
||||
OSLockMutex(&mutex);
|
||||
}
|
||||
|
||||
void BreakPointMgr::unlock() {
|
||||
OSUnlockMutex(&mutex);
|
||||
}
|
||||
|
||||
void BreakPointMgr::cleanup() {
|
||||
lock();
|
||||
breakpoints.cleanup();
|
||||
special.cleanup();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BreakPointMgr::read(void *buffer, uint32_t addr, uint32_t length) {
|
||||
lock();
|
||||
|
||||
memcpy(buffer, (void *)addr, length);
|
||||
|
||||
int index = 0;
|
||||
BreakPoint *bp = findRange(addr, length, &index, true);
|
||||
while (bp) {
|
||||
uint32_t offset = bp->address - addr;
|
||||
char *bufptr = (char *)buffer + offset;
|
||||
if (bp->address > addr + length - 4) {
|
||||
uint32_t value = bp->instruction;
|
||||
for (int i = 0; i < length - offset; i++) {
|
||||
bufptr[i] = value >> 24;
|
||||
value <<= 8;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(uint32_t *)bufptr = bp->instruction;
|
||||
}
|
||||
bp = findRange(addr, length, &index, true);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BreakPointMgr::write(const void *buffer, uint32_t addr, uint32_t length) {
|
||||
lock();
|
||||
|
||||
length = length & ~3;
|
||||
|
||||
int index = 0;
|
||||
if (!findRange(addr, length, &index, true)) {
|
||||
KernelWrite(addr, buffer, length);
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < length; i += 4) {
|
||||
uint32_t value = *(uint32_t *)((char *)buffer + i);
|
||||
|
||||
int index = 0;
|
||||
BreakPoint *bp = findRange(addr + i, 4, &index, true);
|
||||
if (!bp) {
|
||||
KernelWriteU32(addr + i, value);
|
||||
}
|
||||
else {
|
||||
while (bp) {
|
||||
bp->instruction = value;
|
||||
bp = findRange(addr + i, 4, &index, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BreakPointMgr::toggle(uint32_t addr) {
|
||||
lock();
|
||||
|
||||
BreakPoint *bp = find(addr, false);
|
||||
if (bp) {
|
||||
disable(bp);
|
||||
}
|
||||
else {
|
||||
BreakPoint *bp = breakpoints.alloc();
|
||||
bp->isSpecial = false;
|
||||
enable(bp, addr);
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
uint32_t BreakPointMgr::getInstr(uint32_t addr) {
|
||||
lock();
|
||||
uint32_t instruction;
|
||||
BreakPoint *bp = find(addr, true);
|
||||
if (bp) {
|
||||
instruction = bp->instruction;
|
||||
}
|
||||
else {
|
||||
instruction = *(uint32_t *)addr;
|
||||
}
|
||||
unlock();
|
||||
return instruction;
|
||||
}
|
||||
|
||||
void BreakPointMgr::clearSpecial(OSThread *thread) {
|
||||
lock();
|
||||
for (int i = 0; i < special.size(); i++) {
|
||||
SpecialBreakPoint *bp = special[i];
|
||||
if (bp->thread == thread) {
|
||||
disable(bp);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BreakPointMgr::predictStep(ExceptionState *state, bool stepOver) {
|
||||
lock();
|
||||
|
||||
uint32_t address = state->context.srr0;
|
||||
uint32_t instruction = getInstr(address);
|
||||
|
||||
uint32_t target1 = address + 4;
|
||||
uint32_t target2 = 0;
|
||||
|
||||
uint8_t opcode = instruction >> 26;
|
||||
if (opcode == 18) { //Branch
|
||||
bool AA = instruction & 2;
|
||||
bool LK = instruction & 1;
|
||||
|
||||
uint32_t LI = instruction & 0x3FFFFFC;
|
||||
if (LI & 0x2000000) LI -= 0x4000000;
|
||||
|
||||
if (!LK || !stepOver) {
|
||||
if (AA) target1 = LI;
|
||||
else {
|
||||
target1 = address + LI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (opcode == 16) { //Conditional branch
|
||||
bool AA = instruction & 2;
|
||||
bool LK = instruction & 1;
|
||||
|
||||
uint32_t BD = instruction & 0xFFFC;
|
||||
if (BD & 0x8000) BD -= 0x10000;
|
||||
|
||||
if (!LK || !stepOver) {
|
||||
if (AA) target2 = BD;
|
||||
else {
|
||||
target2 = address + BD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (opcode == 19) { //Conditional branch to lr/ctr
|
||||
uint16_t XO = (instruction >> 1) & 0x3FF;
|
||||
bool LK = instruction & 1;
|
||||
|
||||
if (!LK || !stepOver) {
|
||||
if (XO == 16) target2 = state->context.lr;
|
||||
else if (XO == 528) target2 = state->context.ctr;
|
||||
}
|
||||
}
|
||||
|
||||
SpecialBreakPoint *bp = special.alloc();
|
||||
bp->isSpecial = true;
|
||||
bp->thread = state->thread;
|
||||
enable(bp, target1);
|
||||
|
||||
if (target2) {
|
||||
SpecialBreakPoint *bp = special.alloc();
|
||||
bp->isSpecial = true;
|
||||
bp->thread = state->thread;
|
||||
enable(bp, target2);
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
bool ExceptionState::isBreakpoint() {
|
||||
return type == PROGRAM && context.srr1 & 0x20000;
|
||||
}
|
||||
|
||||
void ExceptionState::resume() {
|
||||
OSLoadContext(&context);
|
||||
}
|
||||
|
||||
|
||||
void ExceptionMgr::init() {
|
||||
OSInitMutex(&mutex);
|
||||
}
|
||||
|
||||
void ExceptionMgr::lock() {
|
||||
OSLockMutex(&mutex);
|
||||
}
|
||||
|
||||
void ExceptionMgr::unlock() {
|
||||
OSUnlockMutex(&mutex);
|
||||
}
|
||||
|
||||
void ExceptionMgr::cleanup() {
|
||||
OSMessage message;
|
||||
message.message = Debugger::STEP_CONTINUE;
|
||||
|
||||
lock();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
ExceptionState *state = list[i];
|
||||
OSSendMessage(&state->queue, &message, OS_MESSAGE_FLAGS_BLOCKING);
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
ExceptionState *ExceptionMgr::find(OSThread *thread) {
|
||||
lock();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
ExceptionState *state = list[i];
|
||||
if (state->thread == thread) {
|
||||
unlock();
|
||||
return state;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExceptionState *ExceptionMgr::findOrCreate(OSThread *thread) {
|
||||
lock();
|
||||
ExceptionState *state = find(thread);
|
||||
if (!state) {
|
||||
state = new ExceptionState();
|
||||
state->thread = thread;
|
||||
OSInitMessageQueue(&state->queue, &state->message, 1);
|
||||
list.push_back(state);
|
||||
}
|
||||
unlock();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StepMgr::buffer[96];
|
||||
|
||||
void StepMgr::init() {
|
||||
OSInitMutex(&mutex);
|
||||
usedMask = 0;
|
||||
}
|
||||
|
||||
void StepMgr::lock() {
|
||||
OSLockMutex(&mutex);
|
||||
}
|
||||
|
||||
void StepMgr::unlock() {
|
||||
OSUnlockMutex(&mutex);
|
||||
}
|
||||
|
||||
uint32_t *StepMgr::alloc() {
|
||||
lock();
|
||||
int index = 0;
|
||||
uint32_t mask = usedMask;
|
||||
while (mask & 1) {
|
||||
mask >>= 1;
|
||||
index++;
|
||||
}
|
||||
usedMask |= 1 << index;
|
||||
unlock();
|
||||
|
||||
if (index == 32) {
|
||||
OSFatal("Displaced step allocation failed");
|
||||
}
|
||||
return &buffer[index * 3];
|
||||
}
|
||||
|
||||
void StepMgr::free(int index) {
|
||||
lock();
|
||||
usedMask &= ~(1 << index);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void StepMgr::branchConditional(ExceptionState *state, uint32_t instruction, uint32_t target, bool checkCtr) {
|
||||
Bits<5> BO = (instruction >> 21) & 0x1F;
|
||||
Bits<32> CR = state->context.cr;
|
||||
|
||||
uint32_t BI = (instruction >> 16) & 0x1F;
|
||||
bool LK = instruction & 1;
|
||||
|
||||
if (LK) {
|
||||
state->context.lr = state->context.srr0 + 4;
|
||||
}
|
||||
|
||||
bool ctr_ok = true;
|
||||
if (checkCtr) {
|
||||
if (!BO[2]) {
|
||||
state->context.ctr--;
|
||||
}
|
||||
ctr_ok = BO[2] || ((state->context.ctr != 0) ^ BO[3]);
|
||||
}
|
||||
|
||||
bool cond_ok = BO[0] || (CR[BI] == BO[1]);
|
||||
if (ctr_ok && cond_ok) {
|
||||
state->context.srr0 = target;
|
||||
}
|
||||
}
|
||||
|
||||
void StepMgr::singleStep(ExceptionState *state, uint32_t instruction) {
|
||||
uint8_t opcode = instruction >> 26;
|
||||
|
||||
if (opcode == 18) { //Branch
|
||||
bool AA = instruction & 2;
|
||||
bool LK = instruction & 1;
|
||||
|
||||
uint32_t LI = instruction & 0x3FFFFFC;
|
||||
if (LI & 0x2000000) LI -= 0x4000000;
|
||||
|
||||
if (LK) {
|
||||
state->context.lr = state->context.srr0 + 4;
|
||||
}
|
||||
|
||||
if (AA) state->context.srr0 = LI;
|
||||
else {
|
||||
state->context.srr0 += LI;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (opcode == 16) { //Conditional branch
|
||||
bool AA = instruction & 2;
|
||||
|
||||
uint32_t BD = instruction & 0xFFFC;
|
||||
if (BD & 0x8000) BD -= 0x10000;
|
||||
|
||||
uint32_t target;
|
||||
if (AA) target = BD;
|
||||
else {
|
||||
target = state->context.srr0 + BD;
|
||||
}
|
||||
|
||||
branchConditional(state, instruction, target, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opcode == 19) { //Conditional branch to lr/ctr
|
||||
uint16_t XO = (instruction >> 1) & 0x3FF;
|
||||
|
||||
uint32_t target;
|
||||
if (XO == 16) {
|
||||
branchConditional(state, instruction, state->context.lr, true);
|
||||
return;
|
||||
}
|
||||
else if (XO == 528) {
|
||||
branchConditional(state, instruction, state->context.ctr, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *ptr = alloc();
|
||||
ptr[0] = instruction;
|
||||
ptr[1] = TRAP;
|
||||
ptr[2] = state->context.srr0;
|
||||
DCFlushRange(ptr, 12);
|
||||
ICInvalidateRange(ptr, 12);
|
||||
state->context.srr0 = (uint32_t)ptr;
|
||||
}
|
||||
|
||||
void StepMgr::handleBreakPoint(ExceptionState *state) {
|
||||
uint32_t start = (uint32_t)buffer;
|
||||
uint32_t end = (uint32_t)buffer + sizeof(buffer);
|
||||
|
||||
uint32_t addr = state->context.srr0;
|
||||
if (addr >= start && addr < end) {
|
||||
int offset = addr - start;
|
||||
if (offset % 12 != 4) {
|
||||
char buffer[100];
|
||||
snprintf(buffer, 100, "Unexpected srr0 after displaced step: %08X", addr);
|
||||
OSFatal(buffer);
|
||||
}
|
||||
|
||||
int index = offset / 12;
|
||||
state->context.srr0 = buffer[index * 3 + 2] + 4;
|
||||
free(index);
|
||||
|
||||
state->resume();
|
||||
}
|
||||
}
|
||||
|
||||
void StepMgr::adjustAddress(ExceptionState *state) {
|
||||
uint32_t start = (uint32_t)buffer;
|
||||
uint32_t end = (uint32_t)buffer + sizeof(buffer);
|
||||
|
||||
uint32_t addr = state->context.srr0;
|
||||
if (addr >= start && addr < end) {
|
||||
int index = (addr - start) / 12;
|
||||
state->context.srr0 = buffer[index * 3 + 2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Debugger::checkDataRead(uint32_t addr, uint32_t length) {
|
||||
uint32_t memStart, memSize;
|
||||
OSGetMemBound(MEM2, &memStart, &memSize);
|
||||
|
||||
uint32_t memEnd = memStart + memSize;
|
||||
|
||||
return addr >= 0x10000000 && addr + length <= memEnd;
|
||||
}
|
||||
|
||||
Debugger::StepCommand Debugger::notifyBreak(ExceptionState *state) {
|
||||
OSMessage message;
|
||||
message.message = ExceptionState::PROGRAM;
|
||||
message.args[0] = (uint32_t)&state->context;
|
||||
message.args[1] = sizeof(OSContext);
|
||||
message.args[2] = (uint32_t)state->thread;
|
||||
OSSendMessage(&eventQueue, &message, OS_MESSAGE_FLAGS_BLOCKING);
|
||||
|
||||
OSReceiveMessage(&state->queue, &message, OS_MESSAGE_FLAGS_BLOCKING);
|
||||
return (StepCommand)message.message;
|
||||
}
|
||||
|
||||
void Debugger::resumeBreakPoint(ExceptionState *state) {
|
||||
uint32_t address = state->context.srr0;
|
||||
if (breakpoints.isSoftware(address)) {
|
||||
state->context.srr0 += 4;
|
||||
state->resume();
|
||||
}
|
||||
|
||||
uint32_t instruction = breakpoints.getInstr(state->context.srr0);
|
||||
stepper.singleStep(state, instruction);
|
||||
state->resume();
|
||||
}
|
||||
|
||||
void Debugger::processBreakPoint(ExceptionState *state) {
|
||||
StepCommand command = notifyBreak(state);
|
||||
if (command == STEP_INTO || command == STEP_OVER) {
|
||||
breakpoints.predictStep(state, command == STEP_OVER);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::handleBreakPoint(ExceptionState *state) {
|
||||
if (firstTrap) {
|
||||
firstTrap = false;
|
||||
|
||||
Screen screen;
|
||||
screen.init();
|
||||
screen.drawText(
|
||||
0, 0, "Waiting for debugger connection.\n"
|
||||
"Press the home button to continue without debugger.\n"
|
||||
"You can still connect while the game is running."
|
||||
);
|
||||
screen.flip();
|
||||
|
||||
while (!connected) {
|
||||
uint32_t buttons = GetInput(VPAD_BUTTON_HOME);
|
||||
if (buttons) {
|
||||
state->context.srr0 += 4;
|
||||
state->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stepper.handleBreakPoint(state);
|
||||
|
||||
if (!connected) {
|
||||
handleFatalCrash(state);
|
||||
}
|
||||
|
||||
uint32_t addr = state->context.srr0;
|
||||
bool trap;
|
||||
|
||||
breakpoints.lock();
|
||||
trap = breakpoints.isCustom(addr) || breakpoints.isSoftware(addr) ||
|
||||
breakpoints.findSpecial(addr, state->thread);
|
||||
breakpoints.unlock();
|
||||
|
||||
breakpoints.clearSpecial(state->thread);
|
||||
if (trap) {
|
||||
processBreakPoint(state);
|
||||
}
|
||||
resumeBreakPoint(state);
|
||||
}
|
||||
|
||||
void Debugger::handleFatalCrash(ExceptionState *state) {
|
||||
stepper.adjustAddress(state);
|
||||
if (connected) {
|
||||
OSMessage message;
|
||||
message.message = state->type;
|
||||
message.args[0] = (uint32_t)&state->context;
|
||||
message.args[1] = sizeof(OSContext);
|
||||
message.args[2] = (uint32_t)state->thread;
|
||||
OSSendMessage(&eventQueue, &message, OS_MESSAGE_FLAGS_BLOCKING);
|
||||
|
||||
while (true) {
|
||||
OSReceiveMessage(&state->queue, &message, OS_MESSAGE_FLAGS_BLOCKING);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *type;
|
||||
if (state->type == ExceptionState::DSI) type = "A DSI";
|
||||
else if (state->type == ExceptionState::ISI) type = "An ISI";
|
||||
else {
|
||||
type = "A program";
|
||||
}
|
||||
DumpContext(&state->context, type);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::handleException(OSContext *context, ExceptionState::Type type) {
|
||||
OSThread *thread = OSGetCurrentThread();
|
||||
|
||||
ExceptionState *state = exceptions.findOrCreate(thread);
|
||||
memcpy(&state->context, context, sizeof(OSContext));
|
||||
state->type = type;
|
||||
|
||||
delete context;
|
||||
|
||||
if (state->isBreakpoint()) {
|
||||
handleBreakPoint(state);
|
||||
}
|
||||
else {
|
||||
handleFatalCrash(state);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::exceptionHandler(OSContext *context, ExceptionState::Type type) {
|
||||
debugger->handleException(context, type);
|
||||
}
|
||||
|
||||
bool Debugger::dsiHandler(OSContext *context) {
|
||||
OSContext *info = new OSContext();
|
||||
memcpy(info, context, sizeof(OSContext));
|
||||
context->srr0 = (uint32_t)exceptionHandler;
|
||||
context->gpr[3] = (uint32_t)info;
|
||||
context->gpr[4] = ExceptionState::DSI;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::isiHandler(OSContext *context) {
|
||||
OSContext *info = new OSContext();
|
||||
memcpy(info, context, sizeof(OSContext));
|
||||
context->srr0 = (uint32_t)exceptionHandler;
|
||||
context->gpr[3] = (uint32_t)info;
|
||||
context->gpr[4] = ExceptionState::ISI;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::programHandler(OSContext *context) {
|
||||
OSContext *info = new OSContext();
|
||||
memcpy(info, context, sizeof(OSContext));
|
||||
context->srr0 = (uint32_t)exceptionHandler;
|
||||
context->gpr[3] = (uint32_t)info;
|
||||
context->gpr[4] = ExceptionState::PROGRAM;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Debugger::cleanup() {
|
||||
breakpoints.cleanup();
|
||||
exceptions.cleanup();
|
||||
|
||||
OSMessage message;
|
||||
while (OSReceiveMessage(&eventQueue, &message, OS_MESSAGE_FLAGS_NONE));
|
||||
}
|
||||
|
||||
void Debugger::mainLoop(Client *client) {
|
||||
while (true) {
|
||||
uint8_t cmd;
|
||||
if (!client->recvall(&cmd, 1)) return;
|
||||
|
||||
if (cmd == COMMAND_CLOSE) return;
|
||||
else if (cmd == COMMAND_READ) {
|
||||
uint32_t addr, length;
|
||||
if (!client->recvall(&addr, 4)) return;
|
||||
if (!client->recvall(&length, 4)) return;
|
||||
|
||||
char *buffer = new char[length];
|
||||
breakpoints.read(buffer, addr, length);
|
||||
if (!client->sendall(buffer, length)) {
|
||||
delete buffer;
|
||||
return;
|
||||
}
|
||||
delete buffer;
|
||||
}
|
||||
else if (cmd == COMMAND_WRITE) {
|
||||
uint32_t addr, length;
|
||||
if (!client->recvall(&addr, 4)) return;
|
||||
if (!client->recvall(&length, 4)) return;
|
||||
if (!client->recvall((void *)addr, length)) return;
|
||||
}
|
||||
else if (cmd == COMMAND_WRITE_CODE) {
|
||||
uint32_t addr, length;
|
||||
if (!client->recvall(&addr, 4)) return;
|
||||
if (!client->recvall(&length, 4)) return;
|
||||
|
||||
char *buffer = new char[length];
|
||||
if (!client->recvall(buffer, length)) {
|
||||
delete buffer;
|
||||
return;
|
||||
}
|
||||
breakpoints.write(buffer, addr, length);
|
||||
delete buffer;
|
||||
}
|
||||
else if (cmd == COMMAND_GET_MODULE_NAME) {
|
||||
char name[0x40];
|
||||
int length = 0x40;
|
||||
OSDynLoad_GetModuleName(-1, name, &length);
|
||||
|
||||
length = strlen(name);
|
||||
if (!client->sendall(&length, 4)) return;
|
||||
if (!client->sendall(name, length)) return;
|
||||
}
|
||||
else if (cmd == COMMAND_GET_MODULE_LIST) {
|
||||
OSLockMutex(OSDynLoad_gLoaderLock);
|
||||
|
||||
char buffer[0x1000]; //This should be enough
|
||||
uint32_t offset = 0;
|
||||
OSDynLoad_RPLInfo *current = FirstRPL;
|
||||
while (current) {
|
||||
OSDynLoad_NotifyData *info = current->notifyData;
|
||||
|
||||
uint32_t namelen = strlen(current->name);
|
||||
if (offset + 0x18 + namelen > 0x1000) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t *infobuf = (uint32_t *)(buffer + offset);
|
||||
infobuf[0] = info->textAddr;
|
||||
infobuf[1] = info->textSize;
|
||||
infobuf[2] = info->dataAddr;
|
||||
infobuf[3] = info->dataSize;
|
||||
infobuf[4] = (uint32_t)current->entryPoint;
|
||||
infobuf[5] = namelen;
|
||||
memcpy(&infobuf[6], current->name, namelen);
|
||||
offset += 0x18 + namelen;
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
OSUnlockMutex(OSDynLoad_gLoaderLock);
|
||||
|
||||
if (!client->sendall(&offset, 4)) return;
|
||||
if (!client->sendall(buffer, offset)) return;
|
||||
}
|
||||
else if (cmd == COMMAND_GET_THREAD_LIST) {
|
||||
int state = OSDisableInterrupts();
|
||||
__OSLockScheduler(this);
|
||||
|
||||
char buffer[0x1000]; //This should be enough
|
||||
uint32_t offset = 0;
|
||||
OSThread *current = ThreadList;
|
||||
while (current) {
|
||||
const char *name = OSGetThreadName(current);
|
||||
|
||||
uint32_t namelen = 0;
|
||||
if (name) {
|
||||
namelen = strlen(name);
|
||||
}
|
||||
|
||||
if (offset + 0x1C + namelen > 0x1000) {
|
||||
break;
|
||||
}
|
||||
|
||||
int priority = current->basePriority;
|
||||
if (current->type == 1) {
|
||||
priority -= 0x20;
|
||||
}
|
||||
else if (current->type == 2) {
|
||||
priority -= 0x40;
|
||||
}
|
||||
|
||||
uint32_t *infobuf = (uint32_t *)(buffer + offset);
|
||||
infobuf[0] = (uint32_t)current;
|
||||
infobuf[1] = current->attr & 7;
|
||||
infobuf[2] = priority;
|
||||
infobuf[3] = (uint32_t)current->stackBase;
|
||||
infobuf[4] = (uint32_t)current->stackEnd;
|
||||
infobuf[5] = (uint32_t)current->entryPoint;
|
||||
infobuf[6] = namelen;
|
||||
memcpy(&infobuf[7], name, namelen);
|
||||
offset += 0x1C + namelen;
|
||||
|
||||
current = current->activeLink.next;
|
||||
}
|
||||
|
||||
__OSUnlockScheduler(this);
|
||||
OSRestoreInterrupts(state);
|
||||
|
||||
if (!client->sendall(&offset, 4)) return;
|
||||
if (!client->sendall(buffer, offset)) return;
|
||||
}
|
||||
else if (cmd == COMMAND_GET_STACK_TRACE) {
|
||||
OSThread *thread;
|
||||
if (!client->recvall(&thread, 4)) return;
|
||||
|
||||
ExceptionState *state = exceptions.find(thread);
|
||||
if (state) {
|
||||
uint32_t sp = state->context.gpr[1];
|
||||
uint32_t trace[32];
|
||||
int index = 0;
|
||||
while (checkDataRead(sp, 4)) {
|
||||
sp = *(uint32_t *)sp;
|
||||
if (!checkDataRead(sp, 4)) break;
|
||||
|
||||
trace[index] = *(uint32_t *)(sp + 4);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!client->sendall(&index, 4)) return;
|
||||
if (!client->sendall(trace, index * 4)) return;
|
||||
}
|
||||
else {
|
||||
int index = 0;
|
||||
if (!client->sendall(&index, 4)) return;
|
||||
}
|
||||
}
|
||||
else if (cmd == COMMAND_TOGGLE_BREAKPOINT) {
|
||||
uint32_t address;
|
||||
if (!client->recvall(&address, 4)) return;
|
||||
|
||||
breakpoints.toggle(address);
|
||||
}
|
||||
else if (cmd == COMMAND_POKE_REGISTERS) {
|
||||
OSThread *thread;
|
||||
if (!client->recvall(&thread, 4)) return;
|
||||
|
||||
uint32_t gpr[32];
|
||||
double fpr[32];
|
||||
if (!client->recvall(gpr, 4 * 32)) return;
|
||||
if (!client->recvall(fpr, 8 * 32)) return;
|
||||
|
||||
exceptions.lock();
|
||||
ExceptionState *state = exceptions.find(thread);
|
||||
if (state) {
|
||||
memcpy(state->context.gpr, gpr, 4 * 32);
|
||||
memcpy(state->context.fpr, fpr, 8 * 32);
|
||||
}
|
||||
exceptions.unlock();
|
||||
}
|
||||
else if (cmd == COMMAND_RECEIVE_MESSAGES) {
|
||||
OSMessage messages[10];
|
||||
|
||||
int count = 0;
|
||||
while (count < 10) {
|
||||
if (!OSReceiveMessage(&eventQueue, &messages[count], OS_MESSAGE_FLAGS_NONE)) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!client->sendall(&count, 4)) return;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!client->sendall(&messages[i], sizeof(OSMessage))) return;
|
||||
if (messages[i].args[0]) {
|
||||
void *data = (void *)messages[i].args[0];
|
||||
size_t length = messages[i].args[1];
|
||||
if (!client->sendall(data, length)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cmd == COMMAND_SEND_MESSAGE) {
|
||||
OSMessage message;
|
||||
if (!client->recvall(&message, sizeof(OSMessage))) return;
|
||||
|
||||
OSThread *thread = (OSThread *)message.args[0];
|
||||
|
||||
exceptions.lock();
|
||||
ExceptionState *state = exceptions.find(thread);
|
||||
if (state) {
|
||||
OSSendMessage(&state->queue, &message, OS_MESSAGE_FLAGS_NONE);
|
||||
}
|
||||
exceptions.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::threadFunc() {
|
||||
int result = socket_lib_init();
|
||||
if (result < 0) {
|
||||
OSFatal("Failed to initialize socket library");
|
||||
}
|
||||
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, dsiHandler);
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, isiHandler);
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, programHandler);
|
||||
|
||||
Server server;
|
||||
Client client;
|
||||
|
||||
initialized = true;
|
||||
while (true) {
|
||||
if (!server.init(Socket::TCP)) continue;
|
||||
if (!server.bind(1560)) continue;
|
||||
if (!server.accept(&client)) continue;
|
||||
connected = true;
|
||||
mainLoop(&client);
|
||||
cleanup();
|
||||
connected = false;
|
||||
client.close();
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
|
||||
int Debugger::threadEntry(int argc, void *argv) {
|
||||
debugger->threadFunc();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Debugger::start() {
|
||||
initialized = false;
|
||||
connected = false;
|
||||
firstTrap = true;
|
||||
|
||||
OSInitMessageQueue(&eventQueue, eventMessages, MESSAGE_COUNT);
|
||||
|
||||
breakpoints.init();
|
||||
exceptions.init();
|
||||
stepper.init();
|
||||
|
||||
OSThread *thread = new OSThread();
|
||||
char *stack = new char[0x8000];
|
||||
|
||||
OSCreateThread(
|
||||
thread, threadEntry, 0, 0,
|
||||
stack + STACK_SIZE, STACK_SIZE,
|
||||
0, 12
|
||||
);
|
||||
OSSetThreadName(thread, "Debug Server");
|
||||
OSResumeThread(thread);
|
||||
|
||||
while (!initialized) {
|
||||
OSSleepTicks(OSMillisecondsToTicks(20));
|
||||
}
|
||||
}
|
||||
|
||||
Debugger *debugger;
|
259
src/debugger.h
Normal file
259
src/debugger.h
Normal file
@ -0,0 +1,259 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "kernel.h"
|
||||
#include "socket.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#define MESSAGE_COUNT 10
|
||||
#define STACK_SIZE 0x8000
|
||||
|
||||
#define TRAP 0x7FE00008
|
||||
|
||||
|
||||
template <int N>
|
||||
class Bits {
|
||||
public:
|
||||
Bits(uint32_t value) {
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
bool operator [](int index) {
|
||||
return (value >> (N - index - 1)) & 1;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
|
||||
class ExceptionState {
|
||||
public:
|
||||
enum Type {
|
||||
DSI,
|
||||
ISI,
|
||||
PROGRAM
|
||||
};
|
||||
|
||||
bool isBreakpoint();
|
||||
void resume();
|
||||
|
||||
Type type;
|
||||
OSContext context;
|
||||
|
||||
OSThread *thread;
|
||||
|
||||
OSMessageQueue queue;
|
||||
OSMessage message;
|
||||
};
|
||||
|
||||
|
||||
class ExceptionMgr {
|
||||
public:
|
||||
void init();
|
||||
void lock();
|
||||
void unlock();
|
||||
void cleanup();
|
||||
ExceptionState *find(OSThread *thread);
|
||||
ExceptionState *findOrCreate(OSThread *thread);
|
||||
|
||||
private:
|
||||
OSMutex mutex;
|
||||
std::vector<ExceptionState *> list;
|
||||
};
|
||||
|
||||
|
||||
class BreakPoint {
|
||||
public:
|
||||
bool isRange(uint32_t addr, uint32_t length);
|
||||
|
||||
uint32_t address;
|
||||
uint32_t instruction;
|
||||
bool isSpecial;
|
||||
};
|
||||
|
||||
class SpecialBreakPoint : public BreakPoint {
|
||||
public:
|
||||
OSThread *thread;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class BreakPointList {
|
||||
public:
|
||||
size_t size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
T *alloc() {
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (list[i].address == 0) {
|
||||
return &list[i];
|
||||
}
|
||||
}
|
||||
|
||||
T newBp;
|
||||
newBp.address = 0;
|
||||
newBp.instruction = 0;
|
||||
list.push_back(newBp);
|
||||
return &list.back();
|
||||
}
|
||||
|
||||
T *find(uint32_t addr) {
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (list[i].address == addr) {
|
||||
return &list[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T *findRange(uint32_t addr, uint32_t length, int *index) {
|
||||
int i = *index;
|
||||
while (i < size()) {
|
||||
if (list[i].isRange(addr, length)) {
|
||||
*index = i + 1;
|
||||
return &list[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i > *index) {
|
||||
*index = i;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T *operator [](int index) {
|
||||
return &list[index];
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (list[i].address != 0) {
|
||||
KernelWriteU32(list[i].address, list[i].instruction);
|
||||
list[i].address = 0;
|
||||
list[i].instruction = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> list;
|
||||
};
|
||||
|
||||
|
||||
class BreakPointMgr {
|
||||
public:
|
||||
void init();
|
||||
void lock();
|
||||
void unlock();
|
||||
void cleanup();
|
||||
bool isCustom(uint32_t addr);
|
||||
bool isSoftware(uint32_t addr);
|
||||
bool isSpecial(uint32_t addr);
|
||||
void read(void *buffer, uint32_t addr, uint32_t length);
|
||||
void write(const void *buffer, uint32_t addr, uint32_t length);
|
||||
void toggle(uint32_t addr);
|
||||
uint32_t getInstr(uint32_t addr);
|
||||
BreakPoint *find(uint32_t addr, bool includeSpecial);
|
||||
BreakPoint *findRange(uint32_t addr, uint32_t length, int *index, bool includeSpecial);
|
||||
SpecialBreakPoint *findSpecial(uint32_t addr, OSThread *thread);
|
||||
void clearSpecial(OSThread *thread);
|
||||
void predictStep(ExceptionState *state, bool stepOver);
|
||||
|
||||
private:
|
||||
BreakPoint *alloc();
|
||||
SpecialBreakPoint *allocSpecial();
|
||||
void disable(BreakPoint *bp);
|
||||
void enable(BreakPoint *bp, uint32_t addr);
|
||||
|
||||
BreakPointList<BreakPoint> breakpoints;
|
||||
BreakPointList<SpecialBreakPoint> special;
|
||||
|
||||
OSMutex mutex;
|
||||
};
|
||||
|
||||
|
||||
class StepMgr {
|
||||
public:
|
||||
void init();
|
||||
void lock();
|
||||
void unlock();
|
||||
void singleStep(ExceptionState *state, uint32_t instruction);
|
||||
void handleBreakPoint(ExceptionState *state);
|
||||
void adjustAddress(ExceptionState *state);
|
||||
|
||||
private:
|
||||
static uint32_t buffer[96];
|
||||
|
||||
uint32_t *alloc();
|
||||
void free(int index);
|
||||
void branchConditional(ExceptionState *state, uint32_t instruction, uint32_t target, bool checkCtr);
|
||||
|
||||
OSMutex mutex;
|
||||
|
||||
uint32_t usedMask;
|
||||
};
|
||||
|
||||
|
||||
class Debugger {
|
||||
public:
|
||||
enum StepCommand {
|
||||
STEP_CONTINUE,
|
||||
STEP_INTO,
|
||||
STEP_OVER
|
||||
};
|
||||
|
||||
void start();
|
||||
|
||||
private:
|
||||
enum Command {
|
||||
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
|
||||
};
|
||||
|
||||
static int threadEntry(int argc, void *argv);
|
||||
static bool dsiHandler(OSContext *context);
|
||||
static bool isiHandler(OSContext *context);
|
||||
static bool programHandler(OSContext *context);
|
||||
static void exceptionHandler(OSContext *context, ExceptionState::Type type);
|
||||
|
||||
void threadFunc();
|
||||
void mainLoop(Client *client);
|
||||
void handleException(OSContext *context, ExceptionState::Type type);
|
||||
void handleFatalCrash(ExceptionState *state);
|
||||
void handleBreakPoint(ExceptionState *state);
|
||||
void processBreakPoint(ExceptionState *state);
|
||||
void resumeBreakPoint(ExceptionState *state);
|
||||
StepCommand notifyBreak(ExceptionState *state);
|
||||
void cleanup();
|
||||
|
||||
bool checkDataRead(uint32_t addr, uint32_t length);
|
||||
|
||||
OSMessageQueue eventQueue;
|
||||
OSMessage eventMessages[MESSAGE_COUNT];
|
||||
|
||||
BreakPointMgr breakpoints;
|
||||
ExceptionMgr exceptions;
|
||||
StepMgr stepper;
|
||||
|
||||
bool initialized;
|
||||
bool connected;
|
||||
bool firstTrap;
|
||||
};
|
||||
|
||||
extern Debugger *debugger;
|
51
src/exceptions.cpp
Normal file
51
src/exceptions.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
|
||||
void DumpContext(OSContext *context, const char *excType) {
|
||||
char buffer[1000];
|
||||
snprintf(buffer, 1000,
|
||||
"%s exception occurred!\n"
|
||||
"r0 :%08X r1 :%08X r2 :%08X r3 :%08X r4 :%08X\n"
|
||||
"r5 :%08X r6 :%08X r7 :%08X r8 :%08X r9 :%08X\n"
|
||||
"r10:%08X r11:%08X r12:%08X r13:%08X r14:%08X\n"
|
||||
"r15:%08X r16:%08X r17:%08X r18:%08X r19:%08X\n"
|
||||
"r20:%08X r21:%08X r22:%08X r23:%08X r24:%08X\n"
|
||||
"r25:%08X r26:%08X r27:%08X r28:%08X r29:%08X\n"
|
||||
"r30:%08X r31:%08X LR :%08X CTR:%08X XER:%08X\n"
|
||||
"\n"
|
||||
"SRR0:%08X SRR1:%08X DSISR:%08X DAR:%08X",
|
||||
excType,
|
||||
context->gpr[0], context->gpr[1], context->gpr[2], context->gpr[3],
|
||||
context->gpr[4], context->gpr[5], context->gpr[6], context->gpr[7],
|
||||
context->gpr[8], context->gpr[9], context->gpr[10], context->gpr[11],
|
||||
context->gpr[12], context->gpr[13], context->gpr[14], context->gpr[15],
|
||||
context->gpr[16], context->gpr[17], context->gpr[18], context->gpr[19],
|
||||
context->gpr[20], context->gpr[21], context->gpr[22], context->gpr[23],
|
||||
context->gpr[24], context->gpr[25], context->gpr[26], context->gpr[27],
|
||||
context->gpr[28], context->gpr[29], context->gpr[30], context->gpr[31],
|
||||
context->lr, context->ctr, context->xer, context->srr0, context->srr1,
|
||||
context->dsisr, context->dar
|
||||
);
|
||||
OSFatal(buffer);
|
||||
}
|
||||
|
||||
bool DSIHandler(OSContext *context) {
|
||||
DumpContext(context, "A DSI");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ISIHandler(OSContext *context) {
|
||||
DumpContext(context, "An ISI");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProgramHandler(OSContext *context) {
|
||||
DumpContext(context, "A program");
|
||||
return false;
|
||||
}
|
||||
|
||||
void InstallExceptionHandlers() {
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, DSIHandler);
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, ISIHandler);
|
||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, ProgramHandler);
|
||||
}
|
3
src/exceptions.h
Normal file
3
src/exceptions.h
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
void DumpContext(OSContext *context, const char *excType);
|
||||
void InstallExceptionHandlers();
|
15
src/hbl.h
Normal file
15
src/hbl.h
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define MEM_BASE 0x800000
|
||||
|
||||
struct OsSpecifics {
|
||||
uint32_t OSDynLoad_Acquire;
|
||||
uint32_t OSDynLoad_FindExport;
|
||||
};
|
||||
#define OS_SPECIFICS ((OsSpecifics *)(MEM_BASE + 0x1500))
|
||||
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_RELAUNCH_ON_LOAD -3
|
21
src/input.cpp
Normal file
21
src/input.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
#include "cafe/vpad.h"
|
||||
#include <cstdint>
|
||||
|
||||
uint32_t GetInput(uint32_t mask) {
|
||||
VPADStatus input;
|
||||
int error;
|
||||
VPADRead(0, &input, 1, &error);
|
||||
return input.pressed & mask;
|
||||
}
|
||||
|
||||
uint32_t WaitInput(uint32_t mask) {
|
||||
VPADStatus input;
|
||||
int error;
|
||||
while (true) {
|
||||
VPADRead(0, &input, 1, &error);
|
||||
if (input.pressed & mask) {
|
||||
return input.pressed & mask;
|
||||
}
|
||||
}
|
||||
}
|
7
src/input.h
Normal file
7
src/input.h
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
uint32_t GetInput(uint32_t mask);
|
||||
uint32_t WaitInput(uint32_t mask);
|
28
src/kernel.S
Normal file
28
src/kernel.S
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
.global SCKernelCopyData
|
||||
SCKernelCopyData:
|
||||
// Disable data address translation
|
||||
mfmsr %r6
|
||||
li %r7, 0x10
|
||||
andc %r6, %r6, %r7
|
||||
mtmsr %r6
|
||||
|
||||
// Copy data
|
||||
addi %r3, %r3, -1
|
||||
addi %r4, %r4, -1
|
||||
mtctr %r5
|
||||
SCKernelCopyData_loop:
|
||||
lbzu %r5, 1(%r4)
|
||||
stbu %r5, 1(%r3)
|
||||
bdnz SCKernelCopyData_loop
|
||||
|
||||
// Enable data address translation
|
||||
ori %r6, %r6, 0x10
|
||||
mtmsr %r6
|
||||
blr
|
||||
|
||||
.global KernelCopyData
|
||||
KernelCopyData:
|
||||
li %r0, 0x2500
|
||||
sc
|
||||
blr
|
64
src/kernel.cpp
Normal file
64
src/kernel.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define KERN_SYSCALL_TBL1 0xFFE84C70 //Unknown
|
||||
#define KERN_SYSCALL_TBL2 0xFFE85070 //Games
|
||||
#define KERN_SYSCALL_TBL3 0xFFE85470 //Loader
|
||||
#define KERN_SYSCALL_TBL4 0xFFEAAA60 //Home menu
|
||||
#define KERN_SYSCALL_TBL5 0xFFEAAE60 //Browser
|
||||
|
||||
extern "C" void SCKernelCopyData(uint32_t dst, uint32_t src, uint32_t len);
|
||||
extern "C" void KernelCopyData(uint32_t dst, uint32_t src, uint32_t len);
|
||||
|
||||
void KernelWrite(uint32_t addr, const void *data, uint32_t length) {
|
||||
uint32_t dst = OSEffectiveToPhysical(addr);
|
||||
uint32_t src = OSEffectiveToPhysical((uint32_t)data);
|
||||
KernelCopyData(dst, src, length);
|
||||
DCFlushRange((void *)addr, length);
|
||||
ICInvalidateRange((void *)addr, length);
|
||||
}
|
||||
|
||||
void KernelWriteU32(uint32_t addr, uint32_t value) {
|
||||
uint32_t dst = OSEffectiveToPhysical(addr);
|
||||
uint32_t src = OSEffectiveToPhysical((uint32_t)&value);
|
||||
KernelCopyData(dst, src, 4);
|
||||
DCFlushRange((void *)addr, 4);
|
||||
ICInvalidateRange((void *)addr, 4);
|
||||
}
|
||||
|
||||
/* Write a 32-bit word with kernel permissions */
|
||||
void __attribute__ ((noinline)) kern_write(uint32_t addr, uint32_t value)
|
||||
{
|
||||
asm volatile (
|
||||
"li 3,1\n"
|
||||
"li 4,0\n"
|
||||
"mr 5,%1\n"
|
||||
"li 6,0\n"
|
||||
"li 7,0\n"
|
||||
"lis 8,1\n"
|
||||
"mr 9,%0\n"
|
||||
"mr %1,1\n"
|
||||
"li 0,0x3500\n"
|
||||
"sc\n"
|
||||
"nop\n"
|
||||
"mr 1,%1\n"
|
||||
:
|
||||
: "r"(addr), "r"(value)
|
||||
: "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10",
|
||||
"11", "12"
|
||||
);
|
||||
}
|
||||
|
||||
void PatchSyscall(int index, uint32_t addr) {
|
||||
kern_write(KERN_SYSCALL_TBL1 + index * 4, addr);
|
||||
kern_write(KERN_SYSCALL_TBL2 + index * 4, addr);
|
||||
kern_write(KERN_SYSCALL_TBL3 + index * 4, addr);
|
||||
kern_write(KERN_SYSCALL_TBL4 + index * 4, addr);
|
||||
kern_write(KERN_SYSCALL_TBL5 + index * 4, addr);
|
||||
}
|
||||
|
||||
void kernelInitialize() {
|
||||
PatchSyscall(0x25, (uint32_t)SCKernelCopyData);
|
||||
}
|
11
src/kernel.h
Normal file
11
src/kernel.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void KernelWrite(uint32_t addr, const void *data, uint32_t length);
|
||||
void KernelWriteU32(uint32_t addr, uint32_t value);
|
||||
|
||||
void PatchSyscall(int index, void *ptr);
|
||||
|
||||
void kernelInitialize();
|
26
src/link.ld
Normal file
26
src/link.ld
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
OUTPUT(diibugger.elf)
|
||||
|
||||
ENTRY(entryPoint)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x00802000;
|
||||
.text : {
|
||||
*(.text*);
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*);
|
||||
}
|
||||
.data : {
|
||||
*(.data*);
|
||||
*(.sdata*);
|
||||
}
|
||||
.bss : {
|
||||
*(.bss*);
|
||||
*(.sbss*);
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(*);
|
||||
}
|
||||
}
|
90
src/main.cpp
Normal file
90
src/main.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "cafe/sysapp.h"
|
||||
#include "cafe/nsysnet.h"
|
||||
#include "cafe/vpad.h"
|
||||
#include "cafe/nn_save.h"
|
||||
#include "cafe/nn_act.h"
|
||||
#include "kernel.h"
|
||||
#include "hbl.h"
|
||||
|
||||
#include "patches.h"
|
||||
#include "debugger.h"
|
||||
#include "exceptions.h"
|
||||
#include "screen.h"
|
||||
#include "menu.h"
|
||||
|
||||
|
||||
bool GetTitleIdOnDisk(uint64_t *titleId) {
|
||||
MCPTitleListType title;
|
||||
uint32_t count = 0;
|
||||
|
||||
int handle = MCP_Open();
|
||||
MCP_TitleListByDevice(handle, "odd", &count, &title, sizeof(title));
|
||||
MCP_Close(handle);
|
||||
|
||||
if (count > 0) {
|
||||
*titleId = title.titleId;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int MenuMain() {
|
||||
Screen screen;
|
||||
screen.init();
|
||||
|
||||
Menu menu(&screen);
|
||||
|
||||
Menu::Option result = menu.show();
|
||||
if (result == Menu::Exit) return EXIT_SUCCESS;
|
||||
else if (result == Menu::LaunchDisk) {
|
||||
uint64_t titleId;
|
||||
if (GetTitleIdOnDisk(&titleId)) {
|
||||
SYSLaunchTitle(titleId);
|
||||
}
|
||||
else {
|
||||
menu.setMessage("Please insert a valid disk");
|
||||
}
|
||||
}
|
||||
else if (result == Menu::ReturnToMenu) {
|
||||
SYSLaunchMenu();
|
||||
}
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
}
|
||||
|
||||
int DebuggerMain() {
|
||||
ApplyPatches();
|
||||
debugger = new Debugger();
|
||||
debugger->start();
|
||||
return EXIT_RELAUNCH_ON_LOAD;
|
||||
}
|
||||
|
||||
|
||||
bool firstRun = true;
|
||||
int start() {
|
||||
coreinitInitialize();
|
||||
kernelInitialize();
|
||||
vpadInitialize();
|
||||
sysappInitialize();
|
||||
nsysnetInitialize();
|
||||
nnsaveInitialize();
|
||||
nnactInitialize();
|
||||
|
||||
InstallExceptionHandlers();
|
||||
|
||||
int result;
|
||||
if (firstRun) {
|
||||
result = MenuMain();
|
||||
}
|
||||
else {
|
||||
result = DebuggerMain();
|
||||
}
|
||||
firstRun = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" int entryPoint() {
|
||||
return start();
|
||||
}
|
28
src/memory.cpp
Normal file
28
src/memory.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
void * operator new(size_t size) {
|
||||
return MEMAllocFromDefaultHeap(size);
|
||||
}
|
||||
|
||||
void * operator new[](size_t size) {
|
||||
return MEMAllocFromDefaultHeap(size);
|
||||
}
|
||||
|
||||
void * operator new(size_t size, int alignment) {
|
||||
return MEMAllocFromDefaultHeapEx(size, alignment);
|
||||
}
|
||||
|
||||
void * operator new[](size_t size, int alignment) {
|
||||
return MEMAllocFromDefaultHeapEx(size, alignment);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) {
|
||||
MEMFreeToDefaultHeap(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr, size_t size) {
|
||||
MEMFreeToDefaultHeap(ptr);
|
||||
}
|
7
src/memory.h
Normal file
7
src/memory.h
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
void *operator new(size_t size, int alignment);
|
||||
void *operator new[](size_t size, int alignment);
|
44
src/menu.cpp
Normal file
44
src/menu.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
#include "cafe/vpad.h"
|
||||
#include "menu.h"
|
||||
#include "screen.h"
|
||||
#include "input.h"
|
||||
#include "color.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();
|
||||
}
|
24
src/menu.h
Normal file
24
src/menu.h
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
#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;
|
||||
};
|
57
src/patches.cpp
Normal file
57
src/patches.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
int OSSetExceptionCallback_Patch() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSetExceptionCallbackEx_Patch() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool OSIsDebuggerInitialized_Patch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Patch(void *funcPtr, void *patchPtr) {
|
||||
OSDynLoad_NotifyData *sectionInfo = MainRPL->notifyData;
|
||||
|
||||
uint32_t func = (uint32_t)funcPtr;
|
||||
uint32_t patch = (uint32_t)patchPtr;
|
||||
if (func < 0x01800000) { //OS function (with trampoline)
|
||||
for (uint32_t addr = sectionInfo->textAddr; addr < 0x10000000; addr += 4) {
|
||||
uint32_t *instrs = (uint32_t *)addr;
|
||||
if (instrs[0] == (0x3D600000 | (func >> 16)) && //lis r11, func@h
|
||||
instrs[1] == (0x616B0000 | (func & 0xFFFF)) && //ori r11, r11, func@l
|
||||
instrs[2] == 0x7D6903A6 && //mtctr r11
|
||||
instrs[3] == 0x4E800420) //bctr
|
||||
{
|
||||
KernelWriteU32(addr, 0x3D600000 | (patch >> 16)); //lis r11, patch@h
|
||||
KernelWriteU32(addr + 4, 0x616B0000 | (patch & 0xFFFF)); //ori r11, r11, patch@l
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //Dynamic function
|
||||
for (uint32_t addr = sectionInfo->textAddr; addr < 0x10000000; addr += 4) {
|
||||
uint32_t instr = *(uint32_t *)addr;
|
||||
if ((instr & 0xFC000002) == 0x48000000) { //b or bl
|
||||
if ((instr & 0x03FFFFFC) == func - addr) {
|
||||
instr = instr & ~0x03FFFFFC;
|
||||
instr |= patch;
|
||||
instr |= 2; //Turn b/bl into ba/bla
|
||||
KernelWriteU32(addr, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyPatches() {
|
||||
Patch((void *)OSSetExceptionCallback, (void *)OSSetExceptionCallback_Patch);
|
||||
Patch((void *)OSSetExceptionCallbackEx, (void *)OSSetExceptionCallbackEx_Patch);
|
||||
|
||||
Patch((void *)OSIsDebuggerInitialized, (void *)OSIsDebuggerInitialized_Patch);
|
||||
}
|
4
src/patches.h
Normal file
4
src/patches.h
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
void ApplyPatches();
|
87
src/screen.cpp
Normal file
87
src/screen.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
#include "cafe/coreinit.h"
|
||||
#include "screen.h"
|
||||
#include "memory.h"
|
||||
|
||||
Screen::Screen() : screenBuffer(0) {}
|
||||
Screen::~Screen() {
|
||||
if (screenBuffer) {
|
||||
operator delete(screenBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::init() {
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t bufferSize0 = OSScreenGetBufferSizeEx(0);
|
||||
uint32_t bufferSize1 = OSScreenGetBufferSizeEx(1);
|
||||
screenBuffer = operator new(bufferSize0 + bufferSize1, 0x40);
|
||||
OSScreenSetBufferEx(0, screenBuffer);
|
||||
OSScreenSetBufferEx(1, (char *)screenBuffer + bufferSize0);
|
||||
|
||||
OSScreenEnableEx(0, 1);
|
||||
OSScreenEnableEx(1, 1);
|
||||
OSScreenClearBufferEx(0, 0);
|
||||
OSScreenClearBufferEx(1, 0);
|
||||
OSScreenFlipBuffersEx(0);
|
||||
OSScreenFlipBuffersEx(1);
|
||||
}
|
||||
|
||||
void Screen::clear(Display screen, uint32_t color) {
|
||||
OSScreenClearBufferEx(screen, color);
|
||||
}
|
||||
|
||||
void Screen::drawRect(Display screen, int x1, int y1, int x2, int y2, uint32_t color) {
|
||||
for (int x = x1; x < x2; x++) {
|
||||
OSScreenPutPixelEx(screen, x, y1, color);
|
||||
OSScreenPutPixelEx(screen, x, y2, color);
|
||||
}
|
||||
for (int y = y1; y < y2; y++) {
|
||||
OSScreenPutPixelEx(screen, x1, y, color);
|
||||
OSScreenPutPixelEx(screen, x2, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::fillRect(Display screen, int x1, int y1, int x2, int y2, uint32_t color) {
|
||||
for (int x = x1; x < x2; x++) {
|
||||
for (int y = y1; y < y2; y++) {
|
||||
OSScreenPutPixelEx(screen, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::drawText(Display screen, int x, int y, const char *text) {
|
||||
OSScreenPutFontEx(screen, x, y, text);
|
||||
}
|
||||
|
||||
void Screen::flip(Display screen) {
|
||||
OSScreenFlipBuffersEx(screen);
|
||||
}
|
||||
|
||||
int Screen::convx(int x) { return x * 854 / 1280; }
|
||||
int Screen::convy(int y) { return y * 480 / 720; }
|
||||
|
||||
void Screen::clear(uint32_t color) {
|
||||
clear(TV, color);
|
||||
clear(DRC, color);
|
||||
}
|
||||
|
||||
void Screen::drawRect(int x1, int y1, int x2, int y2, uint32_t color) {
|
||||
drawRect(TV, x1, y1, x2, y2, color);
|
||||
drawRect(DRC, convx(x1), convy(y1), convx(x2), convy(y2), color);
|
||||
}
|
||||
|
||||
void Screen::fillRect(int x1, int y1, int x2, int y2, uint32_t color) {
|
||||
fillRect(TV, x1, y1, x2, y2, color);
|
||||
fillRect(DRC, convx(x1), convy(y1), convx(x2), convy(y2), color);
|
||||
}
|
||||
|
||||
void Screen::drawText(int x, int y, const char *text) {
|
||||
drawText(TV, x, y, text);
|
||||
drawText(DRC, x, y, text);
|
||||
}
|
||||
|
||||
void Screen::flip() {
|
||||
flip(TV);
|
||||
flip(DRC);
|
||||
}
|
34
src/screen.h
Normal file
34
src/screen.h
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
enum Display {
|
||||
TV,
|
||||
DRC
|
||||
};
|
||||
|
||||
Screen();
|
||||
~Screen();
|
||||
|
||||
void init();
|
||||
void clear(uint32_t color);
|
||||
void drawRect(int x1, int y1, int x2, int y2, uint32_t color);
|
||||
void fillRect(int x1, int y1, int x2, int y2, uint32_t color);
|
||||
void drawText(int x, int y, const char *text);
|
||||
void flip();
|
||||
|
||||
void clear(Display screen, uint32_t color);
|
||||
void drawRect(Display screen, int x1, int y1, int x2, int y2, uint32_t color);
|
||||
void fillRect(Display screen, int x1, int y1, int x2, int y2, uint32_t color);
|
||||
void drawText(Display screen, int x, int y, const char *text);
|
||||
void flip(Display screen);
|
||||
|
||||
private:
|
||||
void *screenBuffer;
|
||||
|
||||
int convx(int x);
|
||||
int convy(int y);
|
||||
};
|
101
src/socket.cpp
Normal file
101
src/socket.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
#include "cafe/nsysnet.h"
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
Socket::Socket() : sock(-1) {}
|
||||
|
||||
Socket::~Socket() {
|
||||
if (sock >= 0) {
|
||||
socketclose(sock);
|
||||
}
|
||||
}
|
||||
|
||||
bool Socket::init(Type type) {
|
||||
if (type == TCP) {
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
else {
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
}
|
||||
return sock >= 0;
|
||||
}
|
||||
|
||||
bool Socket::close() {
|
||||
if (sock >= 0) {
|
||||
int result = socketclose(sock);
|
||||
sock = -1;
|
||||
return result == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Client::sendall(const void *data, size_t length) {
|
||||
size_t sent = 0;
|
||||
while (sent < length) {
|
||||
int num = send(sock, data, length - sent, 0);
|
||||
if (num < 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
sent += num;
|
||||
data = (const char *)data + num;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::recvall(void *data, size_t length) {
|
||||
size_t received = 0;
|
||||
while (received < length) {
|
||||
int num = recv(sock, data, length - received, 0);
|
||||
if (num <= 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
received += num;
|
||||
data = (char *)data + num;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Server::bind(int port) {
|
||||
uint32_t reuseaddr = 1;
|
||||
int result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, 4);
|
||||
if (result < 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr serverAddr = {0};
|
||||
serverAddr.family = AF_INET;
|
||||
serverAddr.port = port;
|
||||
serverAddr.addr = 0;
|
||||
|
||||
result = ::bind(sock, &serverAddr, 16);
|
||||
if (result < 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Server::accept(Client *client) {
|
||||
int result = listen(sock, 1);
|
||||
if (result < 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = ::accept(sock, 0, 0);
|
||||
if (fd < 0) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
client->sock = fd;
|
||||
return true;
|
||||
}
|
31
src/socket.h
Normal file
31
src/socket.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class Socket {
|
||||
public:
|
||||
enum Type {
|
||||
TCP,
|
||||
UDP
|
||||
};
|
||||
|
||||
Socket();
|
||||
~Socket();
|
||||
bool init(Type type);
|
||||
bool close();
|
||||
|
||||
int sock;
|
||||
};
|
||||
|
||||
class Client : public Socket {
|
||||
public:
|
||||
bool sendall(const void *data, size_t length);
|
||||
bool recvall(void *data, size_t length);
|
||||
};
|
||||
|
||||
class Server : public Socket {
|
||||
public:
|
||||
bool bind(int port);
|
||||
bool accept(Client *client);
|
||||
};
|
Loading…
Reference in New Issue
Block a user