forked from GitHub/lad
Uploading Lua Assembler/Disassembler for Lua 5.2
This commit is contained in:
@@ -0,0 +1,754 @@
|
||||
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
|
||||
Reference in New Issue
Block a user