Compare commits

..

2 Commits

Author SHA1 Message Date
Enrico Lumetti a65b94e483 Basic bytecode inspection for test1.lua 2022-05-08 00:10:26 +02:00
Enrico Lumetti d800d334dc Implement enough to read bytecode instructions 2022-05-07 23:04:26 +02:00
5 changed files with 205 additions and 76 deletions

14
inspectbc.lua Normal file
View File

@ -0,0 +1,14 @@
local readbc = require('readbc')
local opcodes = require('opcodes')
fp = io.open('tests/test1.luo')
header = readbc.read_header(fp)
proto = readbc.read_proto(fp)
for i = 1, #proto.bcins do
local decoded = opcodes.decode(proto.bcins[i])
local def = opcodes.defs[decoded.id]
print(def.name)
print(decoded.a)
print(decoded.d)
end

View File

@ -2,4 +2,5 @@ local readbc = require('readbc')
fp = io.open('tests/test1.luo')
header = readbc.read_header(fp)
print(header.name)
proto = readbc.read_proto(fp)
print(#proto.bcins)

95
opcodes.lua Normal file
View File

@ -0,0 +1,95 @@
local bit = require('bit')
local function opcode(id, name, a, b, c, metamethod)
return {
id=id,
name=name,
a=a,
b=b,
c=c,
methametod=metamethod,
}
end
local function gen_opcodes(tbl)
res = {}
for i = 1, #tbl do
res[tbl[i].id] = {
name = tbl[i].name,
a = tbl[i].a,
b = tbl[i].b,
c = tbl[i].c,
metamethod = tbl[i].metamethod,
}
end
return res
end
local Mode = {
none = 0,
dst = 1,
base = 2,
var = 3,
rbase = 4,
uv = 5,
lit = 6,
lits = 7,
pri = 8,
num = 9,
str = 10,
tab = 11,
func = 12,
jump = 13,
cdata = 14,
max = 15,
none = 15, -- same as max
}
local Metamethod = {
index = 0,
newindex = 1,
gc = 2,
mode = 3,
eq = 4,
len = 5,
lt = 6,
le = 7,
concat = 8,
call = 9,
add = 10,
sub = 11,
mul = 12,
div = 13,
mod = 14,
pow = 15,
unm = 16,
metatable = 17,
tostring = 18,
}
local Opcodes_defs = gen_opcodes {
opcode(37, 'POW', Mode.dst, Mode.none, Mode.lits, Metamethod.none),
opcode(41, 'KSHORT', Mode.dst, Mode.var, Mode.var, Metamethod.pow),
opcode(75, 'RET0', Mode.rbase, Mode.none, Mode.lit, Mode.none),
}
local function decode(ins)
-- TODO: endianess
local id = bit.band(ins, 0xff)
local a = bit.band(ins, 0xff00) / 0x100
local b = bit.band(ins, 0xff0000) / 0x10000
local c = bit.band(ins, 0xff000000) / 0x1000000
local d = bit.band(ins, 0xffff0000) / 0x10000
return {
id = id,
a = a,
b = b,
c = c,
d = d,
}
end
return {
defs = Opcodes_defs,
decode = decode,
}

View File

@ -5,13 +5,53 @@ local bit=require('bit')
local HEADER_MAGIC = {27, string.byte('L'), string.byte('J')}
local HEADER_FLAG_STRIP = 0x02
local function read_u8(fp)
return string.byte(fp:read(1))
end
local function read_u16(fp)
-- TODO: endianess
local b1 = read_u8(fp)
local b2 = read_u8(fp)
return bit.bor(b2*0x100, b1)
end
local function read_u32(fp)
-- TODO: endianess
local h1 = read_u16(fp)
local h2 = read_u16(fp)
return bit.bor(h2*0x10000, h1)
end
local function read_u8n(fp, n)
return { string.byte(fp:read(n), 1, n) }
end
local function read_u16n(fp, n)
local res = {}
for i = 1, n do
res[i] = read_u16(fp)
end
return res
end
local function read_u32n(fp, n)
local res = {}
for i = 1, n do
res[i] = read_u32(fp)
end
return res
end
local function read_uleb128(fp)
local last_byte = false
local res = 0
local shift = 0
-- the bytes are read from the LSB to the MSB
while not last_byte do
local uleb_byte = string.byte(fp:read(1))
local uleb_byte = read_u8(fp)
res = bit.bor(res, bit.lshift(bit.band(uleb_byte, 0x7f), shift))
if bit.band(uleb_byte, 0x80) == 0 then
@ -22,8 +62,8 @@ local function read_uleb128(fp)
end
local function read_header(fp)
local magic = { string.byte(fp:read(3), 1, 3) }
local version = string.byte(fp:read(1))
local magic = read_u8n(fp, 3)
local version = read_u8(fp)
local flags = read_uleb128(fp)
local name
@ -43,6 +83,57 @@ local function read_header(fp)
end
local function read_proto(fp)
local length = read_uleb128(fp)
-- if the the last read proto was the last one
-- we have reached the end marker, which is a zero
-- this overlaps with a uleb128 zero representation
if length == 0 then
return
end
-- read proto header
local flags = read_u8(fp)
local numparams = read_u8(fp)
local framesize = read_u8(fp)
local numuv = read_u8(fp)
local numkgc = read_uleb128(fp)
local numkn = read_uleb128(fp)
local numbc = read_uleb128(fp)
local debugLen = 0
local debugInfo = nil
if bit.band(flags, HEADER_FLAG_STRIP) ~= 0 then
debugLen = read_uleb128(fp)
-- TODO: is this correct?
if debugLen ~= 0 then
local firstLine = read_uleb128(fp)
local numLine = read_uleb128(fp)
debugInfo = {
firstLine = firstLine,
numLine = numLine,
}
end
end
local bcins = read_u32n(fp, numbc)
local uvdata = read_u16n(fp, numuv)
-- local kgc
-- local numkn
return {
flags = flags,
numparams = numparams,
framesize = framesize,
numuv = numuv,
numkgc = numkgc,
numkn = numkn,
numbc = numbc,
debugInfo = debugInfo,
bcins = bcins,
uvdata = uvdata,
}
end
return {

72
vm.lua
View File

@ -1,73 +1 @@
local funcbc = require('jit.util').funcbc
function opcode(id, name, a, b, c, metamethod)
return {
id=id,
name=name,
a=a,
b=b,
c=c,
methametod=metamethod,
}
end
function gen_opcodes(tbl)
length = #tbl
res = {}
for i=1,length do
res[i] = i+1
end
return res
end
Mode = {
none = 0,
dst = 1,
base = 2,
var = 3,,
rbase = 4,
uv = 5,
lit = 6,
lits = 7,
pri = 8,
num = 9,
str = 10,
tab = 11,
func = 12,
jump = 13,
cdata = 14,
max = 15,
none = 15, -- same as max
}
Metamethod = {
index = 0,
newindex = 1,
gc = 2,
mode = 3,
eq = 4,
len = 5,
lt = 6,
le = 7,
concat = 8,
call = 9,
add = 10,
sub = 11,
mul = 12,
div = 13,
mod = 14,
pow = 15,
unm = 16,
metatable = 17,
tostring = 18,
}
Opcodes = gen_opcodes {
opcode(37, 'POW', Mode.dst, Mode.none, Mode.lits, Metamethod.none),
opcode(41, 'KSHORT', Mode.dst, Mode.var, Mode.var, Metamethod.pow),
}
print(Opcodes[1])
ins, m = funcbc(test1, 3) -- TODO: what is m?
print(ins)
print(m)