mirror of
https://github.com/CPunch/LuaDecompy.git
synced 2025-02-03 05:50:08 +00:00
Compare commits
4 Commits
c37e9a21d8
...
refactor
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c98c3c5a0 | |||
| df8e9f7e83 | |||
| a22aa808e0 | |||
| 935844f274 |
80
lparser.py
80
lparser.py
@@ -231,7 +231,8 @@ class LuaDecomp:
|
|||||||
def __emitOperand(self, a: int, b: str, c: str, op: str) -> None:
|
def __emitOperand(self, a: int, b: str, c: str, op: str) -> None:
|
||||||
self.__setReg(a, "(" + b + op + c + ")")
|
self.__setReg(a, "(" + b + op + c + ")")
|
||||||
|
|
||||||
def __compJmp(self, op: str):
|
# handles conditional jumps
|
||||||
|
def __condJmp(self, op: str, rkBC: bool = True):
|
||||||
instr = self.__getCurrInstr()
|
instr = self.__getCurrInstr()
|
||||||
jmpType = "if"
|
jmpType = "if"
|
||||||
scopeStart = "then"
|
scopeStart = "then"
|
||||||
@@ -254,7 +255,13 @@ class LuaDecomp:
|
|||||||
self.__addExpr("%s not " % jmpType)
|
self.__addExpr("%s not " % jmpType)
|
||||||
else:
|
else:
|
||||||
self.__addExpr("%s " % jmpType)
|
self.__addExpr("%s " % jmpType)
|
||||||
|
|
||||||
|
# write actual comparison
|
||||||
|
if rkBC:
|
||||||
self.__addExpr(self.__readRK(instr.B) + op + self.__readRK(instr.C) + " ")
|
self.__addExpr(self.__readRK(instr.B) + op + self.__readRK(instr.C) + " ")
|
||||||
|
else: # just testing rkB
|
||||||
|
self.__addExpr(op + self.__readRK(instr.B))
|
||||||
|
|
||||||
self.pc += 1 # skip next instr
|
self.pc += 1 # skip next instr
|
||||||
if scopeStart:
|
if scopeStart:
|
||||||
self.__startScope("%s " % scopeStart, self.pc - 1, jmp)
|
self.__startScope("%s " % scopeStart, self.pc - 1, jmp)
|
||||||
@@ -315,48 +322,48 @@ class LuaDecomp:
|
|||||||
def parseInstr(self):
|
def parseInstr(self):
|
||||||
instr = self.__getCurrInstr()
|
instr = self.__getCurrInstr()
|
||||||
|
|
||||||
# python, add switch statements *please*
|
match instr.opcode:
|
||||||
if instr.opcode == Opcodes.MOVE: # move is a fake ABC instr, C is ignored
|
case Opcodes.MOVE: # move is a fake ABC instr, C is ignored
|
||||||
# move registers
|
# move registers
|
||||||
self.__setReg(instr.A, self.__getReg(instr.B))
|
self.__setReg(instr.A, self.__getReg(instr.B))
|
||||||
elif instr.opcode == Opcodes.LOADK:
|
case Opcodes.LOADK:
|
||||||
self.__setReg(instr.A, self.chunk.getConstant(instr.B).toCode())
|
self.__setReg(instr.A, self.chunk.getConstant(instr.B).toCode())
|
||||||
elif instr.opcode == Opcodes.LOADBOOL:
|
case Opcodes.LOADBOOL:
|
||||||
if instr.B == 0:
|
if instr.B == 0:
|
||||||
self.__setReg(instr.A, "false")
|
self.__setReg(instr.A, "false")
|
||||||
else:
|
else:
|
||||||
self.__setReg(instr.A, "true")
|
self.__setReg(instr.A, "true")
|
||||||
elif instr.opcode == Opcodes.GETGLOBAL:
|
case Opcodes.GETGLOBAL:
|
||||||
self.__setReg(instr.A, self.chunk.getConstant(instr.B).data)
|
self.__setReg(instr.A, self.chunk.getConstant(instr.B).data)
|
||||||
elif instr.opcode == Opcodes.GETTABLE:
|
case Opcodes.GETTABLE:
|
||||||
self.__setReg(instr.A, self.__getReg(instr.B) + "[" + self.__readRK(instr.C) + "]")
|
self.__setReg(instr.A, self.__getReg(instr.B) + "[" + self.__readRK(instr.C) + "]")
|
||||||
elif instr.opcode == Opcodes.SETGLOBAL:
|
case Opcodes.SETGLOBAL:
|
||||||
self.__addExpr(self.chunk.getConstant(instr.B).data + " = " + self.__getReg(instr.A))
|
self.__addExpr(self.chunk.getConstant(instr.B).data + " = " + self.__getReg(instr.A))
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
elif instr.opcode == Opcodes.SETTABLE:
|
case Opcodes.SETTABLE:
|
||||||
self.__addExpr(self.__getReg(instr.A) + "[" + self.__readRK(instr.B) + "] = " + self.__readRK(instr.C))
|
self.__addExpr(self.__getReg(instr.A) + "[" + self.__readRK(instr.B) + "] = " + self.__readRK(instr.C))
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
elif instr.opcode == Opcodes.NEWTABLE:
|
case Opcodes.NEWTABLE:
|
||||||
self.__parseNewTable(instr.A)
|
self.__parseNewTable(instr.A)
|
||||||
elif instr.opcode == Opcodes.ADD:
|
case Opcodes.ADD:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " + ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " + ")
|
||||||
elif instr.opcode == Opcodes.SUB:
|
case Opcodes.SUB:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " - ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " - ")
|
||||||
elif instr.opcode == Opcodes.MUL:
|
case Opcodes.MUL:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " * ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " * ")
|
||||||
elif instr.opcode == Opcodes.DIV:
|
case Opcodes.DIV:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " / ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " / ")
|
||||||
elif instr.opcode == Opcodes.MOD:
|
case Opcodes.MOD:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " % ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " % ")
|
||||||
elif instr.opcode == Opcodes.POW:
|
case Opcodes.POW:
|
||||||
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " ^ ")
|
self.__emitOperand(instr.A, self.__readRK(instr.B), self.__readRK(instr.C), " ^ ")
|
||||||
elif instr.opcode == Opcodes.UNM:
|
case Opcodes.UNM:
|
||||||
self.__setReg(instr.A, "-" + self.__getReg(instr.B))
|
self.__setReg(instr.A, "-" + self.__getReg(instr.B))
|
||||||
elif instr.opcode == Opcodes.NOT:
|
case Opcodes.NOT:
|
||||||
self.__setReg(instr.A, "not " + self.__getReg(instr.B))
|
self.__setReg(instr.A, "not " + self.__getReg(instr.B))
|
||||||
elif instr.opcode == Opcodes.LEN:
|
case Opcodes.LEN:
|
||||||
self.__setReg(instr.A, "#" + self.__getReg(instr.B))
|
self.__setReg(instr.A, "#" + self.__getReg(instr.B))
|
||||||
elif instr.opcode == Opcodes.CONCAT:
|
case Opcodes.CONCAT:
|
||||||
count = instr.C-instr.B+1
|
count = instr.C-instr.B+1
|
||||||
concatStr = ""
|
concatStr = ""
|
||||||
|
|
||||||
@@ -365,15 +372,20 @@ class LuaDecomp:
|
|||||||
concatStr += self.__getReg(instr.B + i) + (" .. " if not i == count - 1 else "")
|
concatStr += self.__getReg(instr.B + i) + (" .. " if not i == count - 1 else "")
|
||||||
|
|
||||||
self.__setReg(instr.A, concatStr)
|
self.__setReg(instr.A, concatStr)
|
||||||
elif instr.opcode == Opcodes.JMP:
|
case Opcodes.JMP:
|
||||||
pass
|
pass
|
||||||
elif instr.opcode == Opcodes.EQ:
|
case Opcodes.EQ:
|
||||||
self.__compJmp(" == ")
|
self.__condJmp(" == ")
|
||||||
elif instr.opcode == Opcodes.LT:
|
case Opcodes.LT:
|
||||||
self.__compJmp(" < ")
|
self.__condJmp(" < ")
|
||||||
elif instr.opcode == Opcodes.LE:
|
case Opcodes.LE:
|
||||||
self.__compJmp(" <= ")
|
self.__condJmp(" <= ")
|
||||||
elif instr.opcode == Opcodes.CALL:
|
case Opcodes.TEST:
|
||||||
|
if instr.C == 0:
|
||||||
|
self.__condJmp("", False)
|
||||||
|
else:
|
||||||
|
self.__condJmp("not ", False)
|
||||||
|
case Opcodes.CALL:
|
||||||
preStr = ""
|
preStr = ""
|
||||||
callStr = ""
|
callStr = ""
|
||||||
ident = ""
|
ident = ""
|
||||||
@@ -403,15 +415,15 @@ class LuaDecomp:
|
|||||||
|
|
||||||
self.__addExpr(preStr + callStr)
|
self.__addExpr(preStr + callStr)
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
elif instr.opcode == Opcodes.RETURN:
|
case Opcodes.RETURN:
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
pass # no-op for now
|
pass # no-op for now
|
||||||
elif instr.opcode == Opcodes.FORLOOP:
|
case Opcodes.FORLOOP:
|
||||||
pass # no-op for now
|
pass # no-op for now
|
||||||
elif instr.opcode == Opcodes.FORPREP:
|
case Opcodes.FORPREP:
|
||||||
self.__addExpr("for %s = %s, %s, %s " % (self.__getLocal(instr.A+3), self.__getReg(instr.A), self.__getReg(instr.A + 1), self.__getReg(instr.A + 2)))
|
self.__addExpr("for %s = %s, %s, %s " % (self.__getLocal(instr.A+3), self.__getReg(instr.A), self.__getReg(instr.A + 1), self.__getReg(instr.A + 2)))
|
||||||
self.__startScope("do", self.pc, instr.B)
|
self.__startScope("do", self.pc, instr.B)
|
||||||
elif instr.opcode == Opcodes.SETLIST:
|
case Opcodes.SETLIST:
|
||||||
# LFIELDS_PER_FLUSH (50) is the number of elements that *should* have been set in the list in the *last* SETLIST
|
# LFIELDS_PER_FLUSH (50) is the number of elements that *should* have been set in the list in the *last* SETLIST
|
||||||
# eg.
|
# eg.
|
||||||
# [ 49] LOADK : R[49] K[1] ; load 0.0 into R[49]
|
# [ 49] LOADK : R[49] K[1] ; load 0.0 into R[49]
|
||||||
@@ -427,8 +439,8 @@ class LuaDecomp:
|
|||||||
for i in range(numElems):
|
for i in range(numElems):
|
||||||
self.__addExpr("%s[%d] = %s" % (ident, (startAt + i + 1), self.__getReg(instr.A + i + 1)))
|
self.__addExpr("%s[%d] = %s" % (ident, (startAt + i + 1), self.__getReg(instr.A + i + 1)))
|
||||||
self.__endStatement()
|
self.__endStatement()
|
||||||
elif instr.opcode == Opcodes.CLOSURE:
|
case Opcodes.CLOSURE:
|
||||||
proto = LuaDecomp(self.chunk.protos[instr.B], headChunk=False, scopeOffset=len(self.scope))
|
proto = LuaDecomp(self.chunk.protos[instr.B], headChunk=False, scopeOffset=len(self.scope))
|
||||||
self.__setReg(instr.A, proto.getPseudoCode())
|
self.__setReg(instr.A, proto.getPseudoCode())
|
||||||
else:
|
case _:
|
||||||
raise Exception("unsupported instruction: %s" % instr.toString())
|
raise Exception("unsupported instruction: %s" % instr.toString())
|
||||||
21
lundump.py
21
lundump.py
@@ -1,7 +1,7 @@
|
|||||||
'''
|
'''
|
||||||
l(un)dump.py
|
l(un)dump.py
|
||||||
|
|
||||||
A Lua5.1 cross-platform bytecode deserializer. This module pulls int and size_t sizes from the
|
A Lua5.1 cross-platform bytecode deserializer && serializer. This module pulls int and size_t sizes from the
|
||||||
chunk header, meaning it should be able to deserialize lua bytecode dumps from most platforms,
|
chunk header, meaning it should be able to deserialize lua bytecode dumps from most platforms,
|
||||||
regardless of the host machine.
|
regardless of the host machine.
|
||||||
|
|
||||||
@@ -9,11 +9,9 @@
|
|||||||
as well as read the lundump.c source file from the Lua5.1 source.
|
as well as read the lundump.c source file from the Lua5.1 source.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from multiprocessing.spawn import get_executable
|
|
||||||
import struct
|
import struct
|
||||||
import array
|
import array
|
||||||
from enum import IntEnum, Enum, auto
|
from enum import IntEnum, Enum, auto
|
||||||
from typing_extensions import Self
|
|
||||||
|
|
||||||
class InstructionType(Enum):
|
class InstructionType(Enum):
|
||||||
ABC = auto(),
|
ABC = auto(),
|
||||||
@@ -129,22 +127,21 @@ class Instruction:
|
|||||||
|
|
||||||
def getAnnotation(self, chunk):
|
def getAnnotation(self, chunk):
|
||||||
if self.opcode == Opcodes.MOVE:
|
if self.opcode == Opcodes.MOVE:
|
||||||
return "move R[%d] into R[%d]" % (self.B, self.A)
|
return "R[%d] := R[%d]" % (self.A, self.B)
|
||||||
elif self.opcode == Opcodes.LOADK:
|
elif self.opcode == Opcodes.LOADK:
|
||||||
return "load %s into R[%d]" % (chunk.getConstant(self.B).toCode(), self.A)
|
return "R[%d] := K[%d] (%s)" % (self.A, self.B, chunk.getConstant(self.B).toCode())
|
||||||
elif self.opcode == Opcodes.GETGLOBAL:
|
elif self.opcode == Opcodes.GETGLOBAL:
|
||||||
return 'move _G[%s] into R[%d]' % (chunk.getConstant(self.B).toCode(), self.A)
|
return 'R[%d] := _G[%s]' % (self.A, chunk.getConstant(self.B).toCode())
|
||||||
elif self.opcode == Opcodes.ADD:
|
elif self.opcode == Opcodes.ADD:
|
||||||
return 'add %s to %s, place into R[%d]' % (self.__formatRK(self.C), self.__formatRK(self.B), self.A)
|
return 'R[%d] := %s + %s' % (self.A, self.__formatRK(self.B), self.__formatRK(self.C))
|
||||||
elif self.opcode == Opcodes.SUB:
|
elif self.opcode == Opcodes.SUB:
|
||||||
return 'sub %s from %s, place into R[%d]' % (self.__formatRK(self.C), self.__formatRK(self.B), self.A)
|
return 'R[%d] := %s - %s' % (self.A, self.__formatRK(self.B), self.__formatRK(self.C))
|
||||||
elif self.opcode == Opcodes.MUL:
|
elif self.opcode == Opcodes.MUL:
|
||||||
return 'mul %s to %s, place into R[%d]' % (self.__formatRK(self.C), self.__formatRK(self.B), self.A)
|
return 'R[%d] := %s * %s' % (self.A, self.__formatRK(self.B), self.__formatRK(self.C))
|
||||||
elif self.opcode == Opcodes.DIV:
|
elif self.opcode == Opcodes.DIV:
|
||||||
return 'div %s from %s, place into R[%d]' % (self.__formatRK(self.C), self.__formatRK(self.B), self.A)
|
return 'R[%d] := %s / %s' % (self.A, self.__formatRK(self.B), self.__formatRK(self.C))
|
||||||
elif self.opcode == Opcodes.CONCAT:
|
elif self.opcode == Opcodes.CONCAT:
|
||||||
count = self.C - self.B + 1
|
return "R[%d] := R[%d] .. R[%d]" % (self.A, self.B, self.C)
|
||||||
return "concat %d values from R[%d] to R[%d], store into R[%d]" % (count, self.B, self.C, self.A)
|
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user