forked from GitHub/lad
755 lines
21 KiB
Lua
755 lines
21 KiB
Lua
local ladconf = require("ladconf")
|
|
|
|
local function check_signature(bytecode)
|
|
local sig = string.format(string.format("%o", string.byte(bytecode, 1)))
|
|
sig = sig .. string.char(string.byte(bytecode, 2))
|
|
sig = sig .. string.char(string.byte(bytecode, 3))
|
|
sig = sig .. string.char(string.byte(bytecode, 4))
|
|
sig = string.gsub(sig, "33", "\033")
|
|
if sig ~= ladconf.LUA_SIGNATURE then
|
|
error ("Not a Lua bytecode!")
|
|
end
|
|
end
|
|
|
|
local function check_version(bytecode)
|
|
if string.byte(bytecode, 5) ~= ladconf.LUA_VERSION then
|
|
error ("Disassembler works only with Lua 5.2!")
|
|
end
|
|
end
|
|
|
|
local function check_header(bytecode)
|
|
check_signature(bytecode)
|
|
check_version(bytecode)
|
|
end
|
|
|
|
local function set_auto_flags(bytecode)
|
|
ladconf.ENDIANNESS = string.byte(bytecode, 7)
|
|
ladconf.INT = string.byte(bytecode, 8)
|
|
ladconf.SIZE_T = string.byte(bytecode, 9)
|
|
ladconf.INSTRUCTION = string.byte(bytecode, 10)
|
|
ladconf.LUA_NUMBER = string.byte(bytecode, 11)
|
|
ladconf.INTEGRAL = string.byte(bytecode, 12)
|
|
end
|
|
|
|
local function parse_int(bytecode, k, n)
|
|
local i = "0x"
|
|
local s,e = k + (n-1), k + 1
|
|
for p=s,e,-1 do
|
|
i = i .. string.format("%02x", string.byte(bytecode, p))
|
|
end
|
|
i = i .. string.format("%02x", string.byte(bytecode, k))
|
|
return tonumber(i),k + (n-1)
|
|
end
|
|
|
|
local function parse_instruction(bytecode, k)
|
|
local code = "0x"
|
|
local n = k + (ladconf.INSTRUCTION - 1)
|
|
for i=n,k,-1 do
|
|
code = code .. string.format("%02x", string.byte(bytecode, i))
|
|
end
|
|
return code,k + (ladconf.INSTRUCTION - 1)
|
|
end
|
|
|
|
local function parse_code(bytecode, k, parsed)
|
|
parsed.sizecode,k = parse_int(bytecode, k, ladconf.INT)
|
|
parsed.code = {}
|
|
for i=1,parsed.sizecode do
|
|
parsed.code[i],k = parse_instruction(bytecode, k + 1)
|
|
end
|
|
return k
|
|
end
|
|
|
|
local function setnilvalue(parsed)
|
|
parsed.type = ladconf.LUA_TNIL
|
|
parsed.value = 'nil'
|
|
end
|
|
|
|
local function setbvalue(parsed, boolean)
|
|
parsed.type = ladconf.LUA_TBOOLEAN
|
|
if boolean == 0 then
|
|
parsed.value = 'false'
|
|
end
|
|
parsed.value = 'true'
|
|
end
|
|
|
|
local function setnvalue(parsed, number)
|
|
parsed.type = ladconf.LUA_TNUMBER
|
|
parsed.value = number
|
|
end
|
|
|
|
local function iscntrl(x)
|
|
if (x >= 0 and x <= 31) or (x == 127) then return true end
|
|
return false
|
|
end
|
|
|
|
local function isprint(x)
|
|
return not iscntrl(x)
|
|
end
|
|
|
|
local function fixed_string(str)
|
|
local new_str = ""
|
|
for i=1,string.len(str) do
|
|
char = string.byte(str, i)
|
|
if char == 34 then new_str = new_str .. string.format("\\\"")
|
|
elseif char == 92 then new_str = new_str .. string.format("\\\\")
|
|
elseif char == 7 then new_str = new_str .. string.format("\\a")
|
|
elseif char == 8 then new_str = new_str .. string.format("\\b")
|
|
elseif char == 12 then new_str = new_str .. string.format("\\f")
|
|
elseif char == 10 then new_str = new_str .. string.format("\\n")
|
|
elseif char == 13 then new_str = new_str .. string.format("\\r")
|
|
elseif char == 9 then new_str = new_str .. string.format("\\t")
|
|
elseif char == 11 then new_str = new_str .. string.format("\\v")
|
|
else
|
|
if isprint(char) then
|
|
new_str = new_str .. string.format("%c", char)
|
|
else
|
|
new_str = new_str .. string.format("\\%03d", char)
|
|
end
|
|
end
|
|
end
|
|
return new_str
|
|
end
|
|
|
|
local function setsvalue(parsed, string)
|
|
parsed.type = ladconf.LUA_TSTRING
|
|
parsed.value = fixed_string(string)
|
|
end
|
|
|
|
local function parse_number(bytecode, k)
|
|
sign = 1
|
|
mantissa = string.byte(bytecode, k+6) % 16
|
|
for i=k+5,k,-1 do mantissa = mantissa * 256 + string.byte(bytecode, i) end
|
|
if string.byte(bytecode,k+7) > 127 then sign = -1 end
|
|
exponent = (string.byte(bytecode, k+7) % 128) * 16 + math.floor(string.byte(bytecode, k+6) / 16)
|
|
if exponent == 0 then return 0 end
|
|
mantissa = (math.ldexp(mantissa, -52) + 1) * sign
|
|
return math.ldexp(mantissa, exponent - 1023)
|
|
end
|
|
|
|
local function parse_string(bytecode, k, len)
|
|
local str = ""
|
|
for i=k+1,k+(len-1) do
|
|
local byte = string.byte(bytecode, i)
|
|
if byte ~= 0 then
|
|
str = str .. string.char(byte)
|
|
else
|
|
str = str .. '\0'
|
|
end
|
|
end
|
|
return str
|
|
end
|
|
|
|
local function parse_constants(bytecode, k, parsed)
|
|
parsed.sizek,k = parse_int(bytecode, k, ladconf.INT)
|
|
parsed.k = {}
|
|
for i=1,parsed.sizek do
|
|
k = k + 1
|
|
local t = string.byte(bytecode, k)
|
|
parsed.k[i] = {}
|
|
if t == ladconf.LUA_TNIL then
|
|
setnilvalue(parsed.k[i])
|
|
elseif t == ladconf.LUA_TBOOLEAN then
|
|
k = k + 1
|
|
setbvalue(parsed.k[i], string.byte(bytecode, k))
|
|
elseif t == ladconf.LUA_TNUMBER then
|
|
setnvalue(parsed.k[i], parse_number(bytecode, k + 1))
|
|
k = k + ladconf.LUA_NUMBER
|
|
elseif t == ladconf.LUA_TSTRING then
|
|
local len
|
|
len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T)
|
|
setsvalue(parsed.k[i], parse_string(bytecode, k, len))
|
|
k = k + len
|
|
end
|
|
end
|
|
return k
|
|
end
|
|
|
|
local function parse_upvalues(bytecode, k, parsed)
|
|
parsed.sizeupvalues,k = parse_int(bytecode, k, ladconf.INT)
|
|
parsed.upvalues = {}
|
|
for i=1,parsed.sizeupvalues do
|
|
parsed.upvalues[i] = {}
|
|
parsed.upvalues[i].instack = string.byte(bytecode, k + 1)
|
|
parsed.upvalues[i].idx = string.byte(bytecode, k + 2)
|
|
k = k + 2
|
|
end
|
|
return k
|
|
end
|
|
|
|
local function parse_debug(bytecode, k, parsed)
|
|
local len,n
|
|
len,k = parse_int(bytecode, k, ladconf.SIZE_T)
|
|
parsed.source = parse_string(bytecode, k + 1, len)
|
|
k = k + len
|
|
parsed.sizelineinfo,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.lineinfo = {}
|
|
for i=1,parsed.sizelineinfo do
|
|
parsed.lineinfo[i],k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
end
|
|
parsed.sizelocvars,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.locvars = {}
|
|
for i=1,parsed.sizelocvars do
|
|
parsed.locvars[i] = {}
|
|
len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T)
|
|
parsed.locvars[i].varname = parse_string(bytecode, k, len)
|
|
k = k + len
|
|
parsed.locvars[i].startpc,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.locvars[i].endpc,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
end
|
|
n,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
for i=1,n do
|
|
len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T)
|
|
parsed.upvalues[i].name = parse_string(bytecode, k, len)
|
|
k = k + len
|
|
end
|
|
return k
|
|
end
|
|
|
|
local function parse_function(bytecode, k, parsed)
|
|
parsed.linedefined,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.lastlinedefined,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.numparams,k = string.byte(bytecode, k + 1), k + 1
|
|
parsed.is_vararg,k = string.byte(bytecode, k + 1), k + 1
|
|
parsed.maxstacksize,k = string.byte(bytecode, k + 1), k + 1
|
|
k = parse_code(bytecode, k + 1, parsed)
|
|
k = parse_constants(bytecode, k + 1, parsed)
|
|
parsed.sizep,k = parse_int(bytecode, k + 1, ladconf.INT)
|
|
parsed.p = {}
|
|
for i=1,parsed.sizep do
|
|
parsed.p[i] = {}
|
|
parsed.p[i].parent = parsed.id
|
|
parsed.p[i].id = i
|
|
k = parse_function(bytecode, k, parsed.p[i])
|
|
end
|
|
k = parse_upvalues(bytecode, k + 1, parsed)
|
|
k = parse_debug(bytecode, k + 1, parsed)
|
|
return k
|
|
end
|
|
|
|
local function parse(bytecode)
|
|
local parsed = {}
|
|
set_auto_flags(bytecode)
|
|
parsed.id = 0
|
|
parse_function(bytecode, ladconf.LUAC_HEADERSIZE, parsed)
|
|
return parsed
|
|
end
|
|
|
|
local function get_opcode(i)
|
|
return ladconf.get_bit(i, ladconf.POS_OP, ladconf.SIZE_OP) + 1
|
|
end
|
|
|
|
local function getarg_A(i)
|
|
return ladconf.get_bit(i, ladconf.POS_A, ladconf.SIZE_A)
|
|
end
|
|
|
|
local function getarg_B(i)
|
|
return ladconf.get_bit(i, ladconf.POS_B, ladconf.SIZE_B)
|
|
end
|
|
|
|
local function getarg_C(i)
|
|
return ladconf.get_bit(i, ladconf.POS_C, ladconf.SIZE_C)
|
|
end
|
|
|
|
local function getarg_Bx(i)
|
|
return ladconf.get_bit(i, ladconf.POS_Bx, ladconf.SIZE_Bx)
|
|
end
|
|
|
|
local function getarg_Ax(i)
|
|
return ladconf.get_bit(i, ladconf.POS_Ax, ladconf.SIZE_Ax)
|
|
end
|
|
|
|
local function getarg_sBx(i)
|
|
return getarg_Bx(i) - ladconf.MAXARG_sBx
|
|
end
|
|
|
|
local function get_b_mode(o)
|
|
return ladconf.opmodes[o].B
|
|
end
|
|
|
|
local function get_c_mode(o)
|
|
return ladconf.opmodes[o].C
|
|
end
|
|
|
|
local function ISK(x)
|
|
return ladconf.ISK(x)
|
|
end
|
|
|
|
local function INDEXK(x)
|
|
return ladconf.INDEXK(x)
|
|
end
|
|
|
|
local function MYK(x)
|
|
return (-1-(x))
|
|
end
|
|
|
|
local function UPVALNAME(parsed, x)
|
|
if parsed.upvalues[x].name then
|
|
return parsed.upvalues[x].name
|
|
end
|
|
return "-"
|
|
end
|
|
|
|
local function get_funcline(parsed, pc)
|
|
if parsed.sizelineinfo > 0 then
|
|
return parsed.lineinfo[pc]
|
|
end
|
|
return 0
|
|
end
|
|
|
|
local function print_header(parsed)
|
|
local function SS(x) if x == 1 then return "" else return "s" end end
|
|
local function S(x) return x,SS(x) end
|
|
|
|
local func_name = "function"
|
|
local is_vararg = ""
|
|
|
|
if parsed.linedefined == 0 and parsed.id == 0 then
|
|
func_name = "main"
|
|
end
|
|
if parsed.is_vararg ~= 0 then
|
|
is_vararg = "+"
|
|
end
|
|
|
|
io.write(string.format("\n%s <%s:%d,%d> (%d instruction%s at %d)\n",
|
|
func_name, parsed.source,
|
|
parsed.linedefined, parsed.lastlinedefined,
|
|
parsed.sizecode, SS(parsed.sizecode), 0))
|
|
io.write(string.format("%d%s param%s, %d slot%s, %d upvalue%s, ",
|
|
parsed.numparams, is_vararg, SS(parsed.numparams),
|
|
parsed.maxstacksize, SS(parsed.maxstacksize),
|
|
parsed.sizeupvalues, SS(parsed.sizeupvalues)))
|
|
io.write(string.format("%d local%s, %d constant%s, %d function%s\n",
|
|
parsed.sizelocvars, SS(parsed.sizelocvars),
|
|
parsed.sizek, SS(parsed.sizek),
|
|
parsed.sizep, SS(parsed.sizep)))
|
|
end
|
|
|
|
local function print_string(str)
|
|
io.write(string.format('"%s"', str))
|
|
end
|
|
|
|
local function print_constant(parsed, i)
|
|
if not parsed.k[i] then
|
|
io.write("nil")
|
|
return
|
|
end
|
|
local t = parsed.k[i].type
|
|
local v = parsed.k[i].value
|
|
if t == ladconf.LUA_TNIL or
|
|
t == ladconf.LUA_TBOOLEAN or
|
|
t == ladconf.LUA_TNUMBER then
|
|
io.write(string.format("%s", v))
|
|
elseif t == ladconf.LUA_TSTRING then
|
|
print_string(v)
|
|
end
|
|
end
|
|
|
|
local function print_code(parsed)
|
|
local n = parsed.sizecode
|
|
local pc = 1
|
|
while pc <= n do
|
|
local i = parsed.code[pc]
|
|
local o = get_opcode(i)
|
|
local a = getarg_A(i)
|
|
local b = getarg_B(i)
|
|
local c = getarg_C(i)
|
|
local ax = getarg_Ax(i)
|
|
local bx = getarg_Bx(i)
|
|
local sbx = getarg_sBx(i)
|
|
local line = get_funcline(parsed, pc)
|
|
local opcode = ladconf.OPCODE[o]
|
|
|
|
io.write(string.format("\t%d\t", pc))
|
|
if line > 0 then
|
|
io.write(string.format("[%d]\t", line))
|
|
else
|
|
io.write(string.format("[-]\t"))
|
|
end
|
|
io.write(string.format("%-9s\t", opcode))
|
|
|
|
local opmode = ladconf.get_op_mode(o)
|
|
if opmode == ladconf.iABC then
|
|
io.write(string.format("%d", a))
|
|
local bmode = get_b_mode(o)
|
|
local cmode = get_c_mode(o)
|
|
if bmode ~= ladconf.OpArgN then
|
|
if ISK(b) then
|
|
io.write(string.format(" %d", MYK(INDEXK(b))))
|
|
else
|
|
io.write(string.format(" %d", b))
|
|
end
|
|
end
|
|
if cmode ~= ladconf.OpArgN then
|
|
if ISK(c) then
|
|
io.write(string.format(" %d", MYK(INDEXK(c))))
|
|
else
|
|
io.write(string.format(" %d", c))
|
|
end
|
|
end
|
|
elseif opmode == ladconf.iABx then
|
|
io.write(string.format("%d", a))
|
|
local bmode = get_b_mode(o)
|
|
if bmode == ladconf.OpArgK then
|
|
io.write(string.format(" %d", MYK(bx)))
|
|
end
|
|
if bmode == ladconf.OpArgU then
|
|
io.write(string.format(" %d", bx))
|
|
end
|
|
elseif opmode == ladconf.iAsBx then
|
|
io.write(string.format("%d %d", a, sbx))
|
|
elseif opmode == ladconf.iAx then
|
|
io.write(string.format("%d", MYK(ax)))
|
|
end
|
|
|
|
if opcode == "LOADK" then
|
|
io.write(string.format("\t; "))
|
|
print_constant(parsed, bx+1)
|
|
elseif opcode == "GETUPVAL" or
|
|
opcode == "SETUPVAL" then
|
|
io.write(string.format("\t; %s", UPVALNAME(parsed, b+1)))
|
|
elseif opcode == "GETTABUP" then
|
|
io.write(string.format("\t; %s", UPVALNAME(parsed, b+1)))
|
|
if ISK(c) then
|
|
io.write(string.format(" "))
|
|
print_constant(parsed, INDEXK(c+1))
|
|
end
|
|
elseif opcode == "SETTABUP" then
|
|
io.write(string.format("\t; %s", UPVALNAME(parsed, a+1)))
|
|
if ISK(b) then
|
|
io.write(string.format(" "))
|
|
print_constant(parsed, INDEXK(b+1))
|
|
end
|
|
if ISK(c) then
|
|
io.write(string.format(" "))
|
|
print_constant(parsed, INDEXK(c+1))
|
|
end
|
|
elseif opcode == "GETTABLE" or
|
|
opcode == "SELF" then
|
|
if ISK(c) then
|
|
io.write(string.format("\t; "))
|
|
print_constant(parsed, INDEXK(c+1))
|
|
end
|
|
elseif opcode == "SETTABLE" or
|
|
opcode == "ADD" or
|
|
opcode == "SUB" or
|
|
opcode == "MUL" or
|
|
opcode == "DIV" or
|
|
opcode == "POW" or
|
|
opcode == "EQ" or
|
|
opcode == "LT" or
|
|
opcode == "LE" then
|
|
if ISK(b) or ISK(c) then
|
|
io.write(string.format("\t; "))
|
|
if ISK(b) then
|
|
print_constant(parsed, INDEXK(b+1))
|
|
else
|
|
io.write(string.format("-"))
|
|
end
|
|
io.write(string.format(" "))
|
|
if ISK(c) then
|
|
print_constant(parsed, INDEXK(c+1))
|
|
else
|
|
io.write(string.format("-"))
|
|
end
|
|
end
|
|
elseif opcode == "JMP" or
|
|
opcode == "FORLOOP" or
|
|
opcode == "FORPREP" or
|
|
opcode == "TFORLOOP" then
|
|
io.write(string.format("\t; to %d", sbx+pc+1))
|
|
elseif opcode == "CLOSURE" then
|
|
io.write(string.format("\t; 0x"))
|
|
elseif opcode == "SETLIST" then
|
|
if c == 0 then
|
|
pc = pc + 1
|
|
io.write(string.format("\t; %d", parsed.code[pc]))
|
|
else
|
|
io.write(string.format("\t; %d", c))
|
|
end
|
|
elseif opcode == "EXTRAARG" then
|
|
io.write(string.format("\t; "))
|
|
print_constant(parsed, ax+1)
|
|
end
|
|
io.write(string.format("\n"))
|
|
pc = pc + 1
|
|
end
|
|
end
|
|
|
|
local function print_debug(parsed)
|
|
local n
|
|
n = parsed.sizek
|
|
io.write(string.format("constants (%d) for 0:\n", n))
|
|
for i=1,n do
|
|
io.write(string.format("\t%d\t", i))
|
|
print_constant(parsed, i)
|
|
io.write(string.format("\n"))
|
|
end
|
|
n = parsed.sizelocvars
|
|
io.write(string.format("locals (%d) for 0:\n", n))
|
|
for i=1,n do
|
|
io.write(string.format("\t%d\t%s\t%d\t%d\n", i-1,
|
|
parsed.locvars[i].varname,
|
|
parsed.locvars[i].startpc+1,
|
|
parsed.locvars[i].endpc+1))
|
|
end
|
|
n = parsed.sizeupvalues
|
|
io.write(string.format("upvalues (%d) for 0:\n", n))
|
|
for i=1,n do
|
|
io.write(string.format("\t%d\t%s\t%d\t%d\n", i-1,
|
|
UPVALNAME(parsed, i),
|
|
parsed.upvalues[i].instack,
|
|
parsed.upvalues[i].idx))
|
|
end
|
|
end
|
|
|
|
local function print_function(parsed, full)
|
|
local n = parsed.sizep
|
|
print_header(parsed)
|
|
print_code(parsed)
|
|
if full then print_debug(parsed) end
|
|
for i=1,n do
|
|
print_function(parsed.p[i], full)
|
|
end
|
|
end
|
|
|
|
local function write_header(output, parsed)
|
|
local fname
|
|
local np = parsed.numparams
|
|
if parsed.linedefined == 0 and parsed.id == 0 then
|
|
fname = "main"
|
|
else
|
|
fname = string.format("F_%s_%s", parsed.parent, parsed.id)
|
|
end
|
|
output:write(string.format("\nfunction %s(%s):\n", fname, np))
|
|
end
|
|
|
|
local function write_par(output, x)
|
|
output:write(string.format("%s", x))
|
|
end
|
|
|
|
local function write_sep(output)
|
|
output:write(string.format(", "))
|
|
end
|
|
|
|
local function R(x)
|
|
return "$" .. x
|
|
end
|
|
|
|
local function UpValue(parsed, x)
|
|
return parsed.upvalues[x+1].name
|
|
end
|
|
|
|
local function KST(parsed, x)
|
|
return parsed.k[x+1].value
|
|
end
|
|
|
|
local function Kst(parsed, x)
|
|
local t = parsed.k[x+1].type
|
|
local v = parsed.k[x+1].value
|
|
if t == ladconf.LUA_TNIL or
|
|
t == ladconf.LUA_TBOOLEAN or
|
|
t == ladconf.LUA_TNUMBER then
|
|
return v
|
|
elseif t == ladconf.LUA_TSTRING then
|
|
return '"' .. v .. '"'
|
|
end
|
|
end
|
|
|
|
local function RKST(parsed, x)
|
|
if ISK(x) then
|
|
return KST(parsed, INDEXK(x))
|
|
else
|
|
return R(x)
|
|
end
|
|
end
|
|
|
|
local function RK(parsed, x)
|
|
if ISK(x) then
|
|
return Kst(parsed, INDEXK(x))
|
|
else
|
|
return R(x)
|
|
end
|
|
end
|
|
|
|
local function KPROTO(parsed, x)
|
|
local parent = parsed.p[x+1].parent
|
|
local id = parsed.p[x+1].id
|
|
return string.format("F_%s_%s", parent, id)
|
|
end
|
|
|
|
local function write_code(output, parsed)
|
|
local n = parsed.sizecode
|
|
for pc=1,n do
|
|
local i = parsed.code[pc]
|
|
local o = get_opcode(i)
|
|
local a = getarg_A(i)
|
|
local b = getarg_B(i)
|
|
local c = getarg_C(i)
|
|
local ax = getarg_Ax(i)
|
|
local bx = getarg_Bx(i)
|
|
local sbx = getarg_sBx(i)
|
|
local line = get_funcline(parsed, pc)
|
|
local opcode = ladconf.OPCODE[o]
|
|
|
|
output:write(string.format("\t%d\t", pc))
|
|
output:write(string.format("[%d]\t", line))
|
|
output:write(string.format("%-9s\t", opcode))
|
|
|
|
if opcode == "MOVE" or
|
|
opcode == "UNM" or
|
|
opcode == "NOT" or
|
|
opcode == "LEN" then
|
|
-- R(A) R(B)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, R(b))
|
|
elseif opcode == "LOADK" then
|
|
-- R(A) Kst(Bx)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, Kst(parsed, bx))
|
|
elseif opcode == "LOADKX" then
|
|
-- R(A)
|
|
write_par(output, R(a))
|
|
elseif opcode == "LOADBOOL" or
|
|
opcode == "NEWTABLE" or
|
|
opcode == "CALL" or
|
|
opcode == "TAILCALL" or
|
|
opcode == "SETLIST" then
|
|
-- R(A) B C
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, b)
|
|
write_sep(output)
|
|
write_par(output, c)
|
|
elseif opcode == "LOADNIL" or
|
|
opcode == "RETURN" or
|
|
opcode == "VARARG" then
|
|
-- R(A) B
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, b)
|
|
elseif opcode == "GETUPVAL" or
|
|
opcode == "SETUPVAL" then
|
|
-- R(A) UpValue(B)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, UpValue(parsed, b))
|
|
elseif opcode == "GETTABUP" then
|
|
-- R(A) UpValue(B) RK(C)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, UpValue(parsed, b))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, c))
|
|
elseif opcode == "GETTABLE" or
|
|
opcode == "SELF" then
|
|
-- R(A) R(B) RK(C)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, R(b))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, c))
|
|
elseif opcode == "SETTABUP" then
|
|
-- UpValue(A) RK(B) RK(C)
|
|
write_par(output, UpValue(parsed, a))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, b))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, c))
|
|
elseif opcode == "SETTABLE" or
|
|
opcode == "ADD" or
|
|
opcode == "SUB" or
|
|
opcode == "MUL" or
|
|
opcode == "DIV" or
|
|
opcode == "MOD" or
|
|
opcode == "POW" then
|
|
-- R(A) RK(B) RK(C)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, b))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, c))
|
|
elseif opcode == "CONCAT" then
|
|
-- R(A) R(B) R(C)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, R(b))
|
|
write_sep(output)
|
|
write_par(output, R(c))
|
|
elseif opcode == "JMP" then
|
|
-- A sBx
|
|
write_par(output, a)
|
|
write_sep(output)
|
|
write_par(output, sbx + pc + 1)
|
|
elseif opcode == "EQ" or
|
|
opcode == "LT" or
|
|
opcode == "LE" then
|
|
-- A RK(B) RK(C)
|
|
write_par(output, a)
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, b))
|
|
write_sep(output)
|
|
write_par(output, RK(parsed, c))
|
|
elseif opcode == "TEST" or
|
|
opcode == "TFORCALL" then
|
|
-- R(A) C
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, c)
|
|
elseif opcode == "TESTSET" then
|
|
-- R(A) R(B) C
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, R(b))
|
|
write_sep(output)
|
|
write_par(output, c)
|
|
elseif opcode == "FORLOOP" or
|
|
opcode == "FORPREP" or
|
|
opcode == "TFORLOOP" then
|
|
-- R(A) sBx
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, sbx + pc + 1)
|
|
elseif opcode == "CLOSURE" then
|
|
-- R(A) KPROTO(Bx)
|
|
write_par(output, R(a))
|
|
write_sep(output)
|
|
write_par(output, KPROTO(parsed, bx))
|
|
elseif opcode == "EXTRAARG" then
|
|
-- Ax
|
|
po = get_opcode(parsed.code[pc-1])
|
|
popcode = ladconf.OPCODE[po]
|
|
if popcode == "LOADKX" then
|
|
write_par(output, Kst(parsed, ax))
|
|
elseif popcode == "SETLIST" then
|
|
write_par(output, ax)
|
|
end
|
|
end
|
|
output:write(string.format("\n"))
|
|
end
|
|
end
|
|
|
|
local function write_function(output, parsed)
|
|
local n = parsed.sizep
|
|
write_header(output, parsed)
|
|
write_code(output, parsed)
|
|
for i=1,n do
|
|
write_function(output, parsed.p[i])
|
|
end
|
|
end
|
|
|
|
local function write(filename, parsed)
|
|
local output = assert(io.open(filename, "w"))
|
|
write_function(output, parsed)
|
|
output:close()
|
|
end
|
|
|
|
local disassembler = {
|
|
parse = parse,
|
|
write = write,
|
|
print_function = print_function,
|
|
}
|
|
|
|
return disassembler
|