lunajit/readbc.lua

146 lines
3.1 KiB
Lua

-- module for reading serialized lua bytecode
local bit=require('bit')
local HEADER_MAGIC = {27, string.byte('L'), string.byte('J')}
local 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 = read_u8(fp)
res = bit.bor(res, bit.lshift(bit.band(uleb_byte, 0x7f), shift))
if bit.band(uleb_byte, 0x80) == 0 then
last_byte = true
end
end
return res
end
local function read_header(fp)
local magic = read_u8n(fp, 3)
local version = read_u8(fp)
local flags = read_uleb128(fp)
local name
local stripped
if bit.band(flags, FLAG_STRIP) ~= 0 then
stripped = true
name = ''
else
stripped = false
local nameLen = read_uleb128(fp)
name = fp:read(nameLen)
end
return {
magic = magic,
version = version,
stripped = stripped,
name = name,
}
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, 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 {
read_header = read_header,
read_proto = read_proto,
}