Add files

This commit is contained in:
Yannik Marchand 2018-09-24 10:43:20 +02:00
parent 1fe0c1c77d
commit bbf63715e9
38 changed files with 5147 additions and 0 deletions

16
build.py Normal file
View 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
View 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])

1225
main.py Normal file

File diff suppressed because it is too large Load Diff

248
src/cafe/coreinit.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
void DumpContext(OSContext *context, const char *excType);
void InstallExceptionHandlers();

15
src/hbl.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,4 @@
#pragma once
void ApplyPatches();

87
src/screen.cpp Normal file
View 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
View 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
View 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
View 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);
};