negamartin

LBC_parse

Jul 27th, 2016
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 26.90 KB | None | 0 0
  1. local lbc={};
  2.  
  3. local function readByte(s)
  4.     local b=s.inf[s.count];
  5.     s.count=s.count+1;
  6.     return b;
  7. end
  8. local function skipByte(s,w)
  9.     if s.dbg and w then
  10.         print("byte:"..w.."="..s.inf[s.count]);
  11.     end
  12.     s.count=s.count+1;
  13. end
  14.  
  15. local function readInt(s)
  16.     --[[if intSize==4 then
  17.         count=count+4;
  18.         if bigEndian then return inf[count-4]*2^24+inf[count-3]*2^16+inf[count-2]*2^8+inf[count-1];
  19.         else return inf[count-1]*2^24+inf[count-2]*2^16+inf[count-3]*2^8+inf[count-4]; end
  20.     else]]
  21.     local num=0;
  22.     for i=0,s.intSize-1 do
  23.         if s.bigEndian then
  24.             num=num+s.inf[s.count+s.intSize-i-1]*2^(i*8);
  25.         else
  26.             num=num+s.inf[s.count+i]*2^(i*8);
  27.         end
  28.     end
  29.     s.count=s.count+s.intSize;
  30.     return num;
  31.     --end
  32. end
  33. local function skipInt(s,w)
  34.     if s.dbg and w then
  35.         print("int:"..w.."="..readInt(s));
  36.     else s.count=s.count+s.intSize; end
  37. end
  38.  
  39. local function readSizet(s)
  40.     --[[if sizetSize==4 then
  41.         count=count+4;
  42.         if bigEndian then return inf[count-4]*2^24+inf[count-3]*2^16+inf[count-2]*2^8+inf[count-1];
  43.         else return inf[count-1]*2^24+inf[count-2]*2^16+inf[count-3]*2^8+inf[count-4]; end
  44.     else]]
  45.     local num=0;
  46.     for i=0,s.sizetSize-1 do
  47.         if s.bigEndian then
  48.             num=num+s.inf[s.count+s.sizetSize-i-1]*2^(i*8);
  49.         else
  50.             num=num+s.inf[s.count+i]*2^(i*8);
  51.         end
  52.     end
  53.     s.count=s.count+s.sizetSize;
  54.     return num;
  55.     --end
  56. end
  57. local function skipSizet(s,w)
  58.     if s.dbg and w then
  59.         print("size_t:"..w.."="..readSizet(s));
  60.     else s.count=s.count+s.sizetSize; end
  61. end
  62.  
  63. local function readString(s)
  64.     local ln=readSizet(s);  --Skip null terminator
  65.     if ln==0 then return false; end
  66.     s.count=s.count-1;
  67.     local b={};
  68.     for i=1,ln-1 do
  69.         b[i]=s.inf[s.count+i];
  70.     end
  71.     s.count=s.count+1+ln;
  72.     return string.char(unpack(b));
  73. end
  74. local function skipString(s,w)
  75.     if s.dbg and w then
  76.         local str=readString(s);
  77.         print("string:"..w.."="..(str and ("\""..str.."\"") or "no value"));
  78.     else
  79.         local ln=readSizet(s);
  80.         s.count=s.count+ln;
  81.     end
  82. end
  83.  
  84. local function readDouble(s)
  85.     --Maybe replace this with chunkspy's readdouble?
  86.    
  87.     local dump={string.dump(function()return 0;end):byte(1,-1)};
  88.     if dump[5]~=0x51 or dump[6]~=0 or dump[10]~=4 or dump[11]~=8 or dump[12]~=0 then
  89.         error("Incompatible lua platform for number decoding");
  90.     end
  91.     local tmps={
  92.         inf=dump,
  93.         bigEndian=dump[7]==0,
  94.         intSize=dump[8],
  95.         sizetSize=dump[9],
  96.         count=13,
  97.     }
  98.     skipString(tmps);   --Skip sourceName
  99.     skipInt(tmps);      --Skip firstLine
  100.     skipInt(tmps);      --Skip lastLine
  101.     skipByte(tmps);     --Skip upvalueCount
  102.     skipByte(tmps);     --Skip paramCount
  103.     skipByte(tmps);     --Skip varargFlags
  104.     skipByte(tmps);     --Skip stackSize
  105.     --Skip instructions
  106.     local cs=readInt(tmps);
  107.     for i=1,cs do
  108.         tmps.count=tmps.count+4;
  109.     end
  110.     skipInt(tmps);  --Skip constant list size
  111.     skipByte(tmps); --Skip constant type
  112.     --Got to constant spot, copy double
  113.     if tmps.bigEndian==s.bigEndian then
  114.         for i=0,7 do
  115.             dump[tmps.count+i]=s.inf[s.count+i];
  116.         end
  117.     else
  118.         for i=0,7 do
  119.             dump[tmps.count+i]=s.inf[s.count+7-i];
  120.         end
  121.     end
  122.     local f=loadstring(string.char(unpack(dump)));
  123.     if not f then error("Error decoding number"); end
  124.     s.count=s.count+8;
  125.     return f();
  126. end
  127. local function skipDouble(s,w)
  128.     if s.dbg and w then
  129.         print("number:"..w.."="..tostring(readDouble(s)));
  130.     else s.count=s.count+8; end
  131. end
  132.  
  133. local opMeta;
  134. do
  135.     local opAlias={"a","b","c",type1="typeA",type2="typeB",type3="typeC"};
  136.     opMeta={
  137.         __index=function(t,k)
  138.             local rk=opAlias[k];
  139.             if rk==nil then
  140.                 return rawget(t,k);
  141.             else
  142.                 return rawget(t,rk);
  143.             end
  144.         end,
  145.         __newindex=function(t,k,v)
  146.             local rk=opAlias[k];
  147.             if rk==nil then
  148.                 return rawset(t,k,v);
  149.             else
  150.                 return rawset(t,rk,v);
  151.             end
  152.         end,
  153.     };
  154. end
  155. lbc.codes={
  156.     --Numeric to name
  157.     [0]="move","loadk","loadbool","loadnil","getupval","getglobal","gettable",
  158.     "setglobal","setupval","settable","newtable","self","add","sub","mul","div",
  159.     "mod","pow","unm","not","len","concat","jmp","eq","lt","le","test","testset",
  160.     "call","tailcall","return","forloop","forprep","tforloop","setlist","close",
  161.     "closure","vararg",
  162.  
  163.     --Name to numeric
  164.     move=0,loadk=1,loadbool=2,loadnil=3,getupval=4,getglobal=5,gettable=6,
  165.     setglobal=7,setupval=8,settable=9,newtable=10,self=11,add=12,sub=13,mul=14,div=15,
  166.     mod=16,pow=17,unm=18,_not=19,["not"]=19,len=20,concat=21,jmp=22,eq=23,lt=24,le=25,
  167.     test=26,testset=27,call=28,tailcall=29,_return=30,["return"]=30,forloop=31,
  168.     forprep=32,tforloop=33,setlist=34,close=35,closure=36,vararg=37,
  169. };
  170. lbc.types={
  171.     ABC=1,ABx=2,AsBx=3,
  172.  
  173.     [0]=1,  --move A B c
  174.     2,      --loadk A Bx
  175.     1,      --loadbool A B C
  176.     1,      --loadnil A B c
  177.     1,      --getupval A B c
  178.     2,      --getglobal A Bx
  179.     1,      --gettable A B C
  180.     2,      --setglobal A Bx
  181.     1,      --setupval A B c
  182.     1,      --settable A B C
  183.     1,      --newtable A B C
  184.     1,      --self A B C
  185.     1,      --add A B C
  186.     1,      --sub A B C
  187.     1,      --mul A B C
  188.     1,      --div A B C
  189.     1,      --mod A B C
  190.     1,      --pow A B C
  191.     1,      --unm A B c
  192.     1,      --not A B c
  193.     1,      --len A B c
  194.     1,      --concat A B C
  195.     3,      --jmp a sBx
  196.     1,      --eq A B C
  197.     1,      --lt A B C
  198.     1,      --le A B C
  199.     1,      --test A b C
  200.     1,      --testset A B C
  201.     1,      --call A B C
  202.     1,      --tailcall A B C
  203.     1,      --return A B c
  204.     3,      --forloop A sBx
  205.     3,      --forprep A sBx
  206.     1,      --tforloop A b C
  207.     1,      --setlist A B C
  208.     1,      --close A b c
  209.     2,      --closure A Bx
  210.     1,      --vararg A B c
  211. };
  212. lbc.insertOp=function(bm,i,iop)
  213.     if iop==nil then
  214.         iop=i;
  215.         i=iop.i;
  216.     else
  217.         iop.i=i;
  218.     end
  219.     for j,jop in ipairs(bm.code) do
  220.         local a,b=lbc.getTargets(jop);
  221.         if b=="code" then   --If op is a jump, update jump
  222.             b=j+1+jop.b;
  223.             if b<i and j>=i then jop.b=jop.b-1;
  224.             elseif b>=i and j<i then jop.b=jop.b+1;
  225.             end
  226.         end
  227.         if j>=i then        --Push ops upwards
  228.             jop.i=jop.i+1;
  229.         end
  230.     end
  231.     table.insert(bm.code,i,iop);
  232. end
  233. lbc.insertMany=function(bm,i,iops)
  234.     local code=bm.code;
  235.     local ioplen=#iops;
  236.     for j=1,#code do
  237.         local jop=code[j];
  238.         local a,b=lbc.getTargets(jop);
  239.         if b=="code" then   --If op is a jump, update jump
  240.             b=j+1+jop.b;
  241.             if b<i and j>=i then jop.b=jop.b-ioplen;
  242.             elseif b>=i and j<i then jop.b=jop.b+ioplen;
  243.             end
  244.         end
  245.         if j>=i then        --Push ops upwards
  246.             jop.i=j+ioplen;
  247.         end
  248.     end
  249.     --Actually insert ops
  250.     for j=1,ioplen do
  251.         table.insert(code,i+j-1,iops[j]);
  252.     end
  253. end
  254. lbc.asm=function(asm)
  255.     for i=1,#asm do
  256.         local args=asm[i];
  257.         local op=setmetatable({name=args[1]},opMeta);
  258.         local stacks={lbc.getTargets(op)};
  259.         local mode=false;
  260.         local num=1;
  261.         for j=2,#args do
  262.             while not stacks[num] do num=num+1; end
  263.             if num>3 then
  264.                 error("op "..i..": too many args",2);
  265.             end
  266.             local fakearg=args[j];
  267.             if mode=="p" or mode=="k" or mode=="pk" then
  268.                 op.marked=true;
  269.                 op[10+num]=mode;
  270.                 op[20+num]=fakearg;
  271.                 num=num+1;
  272.                 mode=false;
  273.             else
  274.                 if fakearg=="k" or fakearg=="pk" or fakearg=="p" then
  275.                     mode=fakearg;
  276.                 elseif fakearg=="knil" then
  277.                     op.marked=true;
  278.                     op[10+num]="k";
  279.                     op[20+num]=nil;
  280.                     num=num+1;
  281.                 elseif type(fakearg)=="number" then
  282.                     op[num]=fakearg;
  283.                     num=num+1;
  284.                 elseif type(fakearg)=="string" and fakearg:sub(1,1)=="t" then
  285.                     op["type"..num]=fakearg:sub(2);
  286.                 else error("op "..i..": invalid arg "..tostring(fakearg)..", only numbers, 'k', 'p' or 'pk'",2); end
  287.             end
  288.         end
  289.         if mode then error("op "..i..": '"..mode.."' missing constant value",2); end
  290.         asm[i]=op;
  291.     end
  292.     return asm;
  293. end
  294. lbc.insertAsm=function(bm,i,asm,ph)
  295.     if asm.stackSize and asm.stackSize>bm.header.stackSize then bm.header.stackSize=asm.stackSize; end
  296.     local code={};
  297.     for j=1,#asm do
  298.         local op=asm[j];
  299.         local newop=op;
  300.         local stacks={lbc.getTargets(op)};
  301.         if op.marked then   --Marked ops need to be "deep-copied"
  302.             newop=setmetatable({name=op.name},opMeta);
  303.         end
  304.        
  305.         for k=1,3 do
  306.             local special=op[10+k];
  307.             if stacks[k]==nil then
  308.             elseif special then
  309.                 local val=op[20+k];
  310.                 if special=="p" or special=="pk" then val=ph[val]; end
  311.                 if special=="k" or special=="pk" then
  312.                     val=bm:k(val);
  313.                     if stacks[k]=="mixed" then val=val+256; end
  314.                 end
  315.                 newop[k]=val;
  316.                 newop["type"..k]=op["type"..k];
  317.             elseif op.marked then
  318.                 newop[k]=op[k];
  319.                 newop["type"..k]=op["type"..k];
  320.             end
  321.         end
  322.         code[j]=newop;
  323.     end
  324.     return lbc.insertMany(bm,i,code);
  325. end
  326. local function getRK(p,t)
  327.     p=lbc.typeToRaw(t,p);
  328.     if not p then return "mixed"; end
  329.     return (p/2^8)%2<1 and "registers" or "constants";
  330. end
  331. lbc.getTargets=function(op)
  332.     local name=op.name;
  333.     if name=="move" or name=="loadnil" or name=="unm" or name=="not" or name=="len" then
  334.         return "registers","registers";
  335.     elseif name=="loadk" or name=="getglobal" or name=="setglobal" then
  336.         return "registers","constants";
  337.     elseif name=="loadbool" or name=="call" or name=="newtable" or name=="setlist" then
  338.         return "registers","staticValues","staticValues";
  339.     elseif name=="getupval" or name=="setupval" then
  340.         return "registers","upvalues";
  341.     elseif name=="gettable" or name=="self" then
  342.         return "registers","registers",getRK(op.c,op.typeC);
  343.     elseif name=="settable" or name=="add" or name=="sub" or name=="mul" or name=="div" or name=="mod" or name=="pow" then
  344.         return "registers",getRK(op.b,op.typeB),getRK(op.c,op.typeC);
  345.     elseif name=="concat" then
  346.         return "registers","registers","registers";
  347.     elseif name=="jmp" then
  348.         return nil,"code";
  349.     elseif name=="return" or name=="tailcall" or name=="vararg" then
  350.         return "registers","staticValues";
  351.     elseif name=="eq" or name=="lt" or name=="le" then
  352.         return "staticValues",getRK(op.b,op.typeB),getRK(op.c,op.typeC);
  353.     elseif name=="test" then
  354.         return "registers",nil,"staticValues";
  355.     elseif name=="testset" then
  356.         return "registers","registers","staticValues";
  357.     elseif name=="forprep" or name=="forloop" then
  358.         return "registers","code";
  359.     elseif name=="tforloop" then
  360.         return "registers",nil,"staticValues";
  361.     elseif name=="closure" then
  362.         return "registers","functions";
  363.     elseif name=="close" then
  364.         return "registers";
  365.     elseif name=="setlist_c" then
  366.         return nil,nil,"staticValues";
  367.     else
  368.         error("Invalid opcode "..tostring(name),2);
  369.     end
  370. end
  371. lbc.new=function(name,a,b,c)
  372.     return setmetatable({name=name,a=a,b=b,c=c},opMeta);
  373. end
  374. lbc.addConstant=function(bm,val)
  375.     local ks=bm.constants;
  376.     for i,kval in ipairs(ks) do
  377.         if val==kval then
  378.             return i-1; --Constant list starts at 0, not 1
  379.         end
  380.     end
  381.     ks.size=ks.size+1;
  382.     ks[ks.size]=val;
  383.     return ks.size-1;   --Constant list starts at 0, not 1
  384. end
  385.  
  386. do
  387.     local frexp=math.frexp; --Upvalues are ALOTFASTER than getglobal+gettable
  388.     lbc.toBytefloat=function(num)
  389.         if num>=8 then
  390.             local _,n=frexp(num);
  391.             n=n-4;  --This lines get the number of bits to shift to the right, such that the leftmost 1 is the 4th bit
  392.             num=num/2^n;    --Shift n bits to the right
  393.             local mn=num%1; --Save the decimal part
  394.             num=(num-mn)%8; --First floor the number and then BAND the rightmost 3 bits
  395.             num=num+(n+1)*2^3;  --BOR the exponent+1 shifted to the left by 3
  396.             if mn~=0 then   --If the number should be rounded up
  397.                 num=num+1;  --Add one to the mantissa. If it overflows it will overflow into the exponent (which is what we want)
  398.             end
  399.         end
  400.         return num;
  401.     end
  402. end
  403. lbc.fromBytefloat=function(bf)
  404.     local e;
  405.     e=bf/(2^3);     --Shift 3 to the right
  406.     e=e-(e%1);      --math.floor without function calls
  407.     local m=bf%(8); --BAND the rightmost 3 bits
  408.     if e==0 then
  409.         return m;
  410.     else
  411.         return (m+8)*(2^(e-1)); --Add the bit #4 to the mantissa, and shift the bits by the amount indicated by the exponent
  412.     end
  413. end
  414.  
  415. local function readInstruction(s)
  416.     local code;
  417.     s.count=s.count+4;
  418.     if s.bigEndian then code=s.inf[s.count-4]*2^24+s.inf[s.count-3]*2^16+s.inf[s.count-2]*2^8+s.inf[s.count-1];
  419.     else code=s.inf[s.count-1]*2^24+s.inf[s.count-2]*2^16+s.inf[s.count-3]*2^8+s.inf[s.count-4]; end
  420.    
  421.     local name,a,b,c;
  422.     local opcode=bit32.band(code,0x0000003F);   --6 bits
  423.     name=lbc.codes[opcode];
  424.     local optype=lbc.types[opcode];
  425.     a=bit32.rshift(bit32.band(code,0x00003FC0),6);  --8 bits
  426.     if optype==lbc.types.ABC then
  427.         c=bit32.rshift(bit32.band(code,0x007FC000),14); --9 bits
  428.         b=bit32.rshift(bit32.band(code,0xFF800000),23); --9 bits
  429.     else
  430.         b=bit32.rshift(bit32.band(code,0xFFFFC000),14); --18 bits
  431.         if optype==lbc.types.ABx then
  432.         elseif optype==lbc.types.AsBx then
  433.             b=b-0x1FFFF;    --Signed in bias format
  434.         else error("Invalid opcode "..tostring(opcode)); end
  435.     end
  436.     return lbc.new(name,a,b,c);
  437. end
  438. local function skipInstruction(s,w)
  439.     if s.dbg and w then
  440.         local op=readInstruction(s);
  441.         print(op.name,op.a,op.b,op.c);
  442.     else s.count=s.count+4; end
  443. end
  444.  
  445. local funcMeta={k=lbc.addConstant};
  446. funcMeta.__index=funcMeta;
  447. local function readFunc(s)
  448.     local bm=setmetatable({},funcMeta);
  449.  
  450.     --Read function header
  451.     if s.skipHeader then
  452.         skipString(s,"sourceName");
  453.         skipInt(s,"firstLine");
  454.         skipInt(s,"lastLine");
  455.         skipByte(s,"upvalueCount");
  456.         skipByte(s,"paramCount");
  457.         skipByte(s,"varargFlags");
  458.         skipByte(s,"stackSize");
  459.     else
  460.         bm.header={};
  461.         bm.header.sourceName=readString(s);
  462.         bm.header.firstLine=readInt(s);
  463.         bm.header.lastLine=readInt(s);
  464.         bm.header.upvalueCount=readByte(s);
  465.         bm.header.paramCount=readByte(s);
  466.         local flags=readByte(s);
  467.         bm.header.varargFlags={hasArg=bit32.band(flags,1)~=0,isVararg=bit32.band(flags,2)~=0,needsArg=bit32.band(flags,4)~=0};
  468.         bm.header.stackSize=readByte(s);
  469.     end
  470.  
  471.     --Read instructions
  472.     local codeSize=readInt(s);
  473.     local op;
  474.     if s.skipCode then
  475.         for i=1,codeSize do
  476.             skipInstruction(s,"instruction");
  477.         end
  478.     else
  479.         local prevOp;
  480.         bm.code={};
  481.         for i=1,codeSize do
  482.             if prevOp and prevOp.name=="setlist" and prevOp.c==0 then
  483.                 --SETLIST's 3rd arg is encoded in this instruction
  484.                 s.count=s.count+4;
  485.                 local c;
  486.                 if s.bigEndian then c=s.inf[s.count-4]*2^24+s.inf[s.count-3]*2^16+s.inf[s.count-2]*2^8+s.inf[s.count-1];
  487.                 else c=s.inf[s.count-1]*2^24+s.inf[s.count-2]*2^16+s.inf[s.count-3]*2^8+s.inf[s.count-4]; end
  488.                 prevOp=lbc.new("setlist_c",nil,nil,c);
  489.             else
  490.                 prevOp=readInstruction(s);
  491.             end
  492.             prevOp.i=i;
  493.             bm.code[i]=prevOp;
  494.         end
  495.     end
  496.  
  497.     --Read constants
  498.     local kSize=readInt(s);
  499.     local kType;
  500.     if s.skipK then
  501.         for i=1,kSize do
  502.             kType=readByte(s);
  503.             if kType==0 then
  504.             elseif kType==1 then
  505.                 skipByte(s,"boolK");
  506.             elseif kType==3 then
  507.                 skipDouble(s,"numberK");
  508.             elseif kType==4 then
  509.                 skipString(s,"stringK");
  510.             else error("Invalid constant type "..kType); end
  511.         end
  512.     else
  513.         bm.constants=setmetatable({size=kSize},{
  514.         __index=function(t,k)
  515.             if type(k)=="number" then
  516.                 --Allow for constants to be fetched with MSB notation
  517.                 if k>=257 then  --Starts at 1, not 0, so 256 refers to register 256, while 257 refers to constant 1
  518.                     return rawget(t,k-256);
  519.                 end
  520.             end
  521.             return rawget(t,k);
  522.         end,
  523.         __newindex=function(t,k,v)
  524.             if type(k)=="number" then
  525.                 if k>=257 then
  526.                     return rawset(t,k-256,v);
  527.                 end
  528.             end
  529.             return rawset(t,k,v);
  530.         end,
  531.         });
  532.         for i=1,kSize do
  533.             kType=readByte(s);
  534.             if kType==0 then
  535.             elseif kType==1 then
  536.                 bm.constants[i]=readByte(s)~=0;
  537.             elseif kType==3 then
  538.                 bm.constants[i]=readDouble(s);
  539.             elseif kType==4 then
  540.                 bm.constants[i]=readString(s);
  541.             else error("Invalid constant type "..kType); end
  542.         end
  543.     end
  544.  
  545.     --Read function prototypes (unskippable)
  546.     local pSize=readInt(s);
  547.     bm.functions={};
  548.     for i=1,pSize do
  549.         bm.functions[i]=readFunc(s);
  550.     end
  551.  
  552.     --Read source lines
  553.     local lineInfoSize=readInt(s);
  554.     if s.skipSourceLines then
  555.         for i=1,lineInfoSize do
  556.             skipInt(s,"sourceLine");
  557.         end
  558.     else
  559.         bm.sourceLines={};
  560.         for i=1,lineInfoSize do
  561.             bm.sourceLines[i]=readInt(s);
  562.         end
  563.     end
  564.  
  565.     --Read local vars
  566.     local locVarSize=readInt(s);
  567.     if s.skipLocalVars then
  568.         for i=1,locVarSize do
  569.             skipString(s,"localVarName");
  570.             skipInt(s,"localVarStartpc");
  571.             skipInt(s,"localVarEndpc");
  572.         end
  573.     else
  574.         bm.localVars={};
  575.         for i=1,locVarSize do
  576.             bm.localVars[i]={
  577.                 name=readString(s),
  578.                 startScope=readInt(s),
  579.                 endScope=readInt(s),
  580.             };
  581.         end
  582.     end
  583.  
  584.     --Read upvalue list
  585.     local upValueSize=readInt(s);
  586.     if s.skipUpvalues then
  587.         for i=1,upValueSize do
  588.             skipString(s,"upvalueName");
  589.         end
  590.     else
  591.         bm.upvalues={};
  592.         for i=1,upValueSize do
  593.             bm.upvalues[i]=readString(s);
  594.         end
  595.     end
  596.  
  597.     return bm;
  598. end
  599.  
  600. --Converts a binary chunk (or function) to a bytemap
  601. lbc.chunkToBytemap=function(chunk,s)
  602.     s=s or {};
  603.     if type(chunk)=="function" then chunk=string.dump(chunk); end
  604.     if type(chunk)=="string" then chunk={chunk:byte(1,-1)}; end
  605.     s.inf=chunk;
  606.     if s.inf[5]~=0x51 then
  607.         print("Bytecode version: "..bit32.rshift(s.inf[5],4).."."..bit32.band(s.inf[5],0x0F));
  608.         error("Parser only works on Lua 5.1 bytecode",0);
  609.     elseif s.inf[6]~=0 then
  610.         print("Bytecode format: "..s.inf[6]);
  611.         error("Parser only works on official bytecode format (format 0)",0);
  612.     elseif s.inf[10]~=4 then
  613.         print("Instruction size: "..(s.inf[10]*8).."-bit");
  614.         error("Parser only works on 32-bit instructions",0);
  615.     elseif s.inf[11]~=8 or s.inf[12]~=0 then
  616.         print("Numbers: "..(s.inf[11]*8).."-bit "..(s.inf[12]==0 and "floating point" or "integral"));
  617.         error("Parser only works on 64-bit floating point numbers",0);
  618.     end
  619.     s.count=1;
  620.     s.bigEndian=s.inf[7]==0;
  621.     s.intSize=s.inf[8];
  622.     s.sizetSize=s.inf[9];
  623.     --print((s.bigEndian and "Big endian, " or "Little endian, ")..(s.intSize*8).."-bit integer, "..(s.sizetSize*8).."-bit size_t");
  624.     s.count=s.count+12;
  625.     local bm=readFunc(s);
  626.     if s.count~=#s.inf+1 then error("Extra bytes in file"); end
  627.     bm.chunkHeader={
  628.         luaVersion=bit32.rshift(s.inf[5],4).."."..bit32.band(s.inf[5],0x0F),
  629.         luaVersionCode=s.inf[5],
  630.         format=s.inf[6]==0 and "official" or "unknown",
  631.         formatNumber=s.inf[6],
  632.         instructionSize=s.inf[10],
  633.         numberSize=s.inf[11],
  634.         numberType=s.inf[12]==0 and "floating_point" or "integer",
  635.         endianness=s.bigEndian and "big" or "little",
  636.         bigEndian=s.bigEndian,
  637.         littleEndian=not s.bigEndian,
  638.         intSize=s.intSize,
  639.         sizetSize=s.sizetSize,
  640.         parserVersion=1,
  641.     };
  642.     return bm;
  643. end
  644. lbc.stringToBytemap=function(str,s)
  645.     if str:sub(1,4)=="\27Lua" then
  646.         local f,err=loadstring(str);
  647.         if f then
  648.             str=string.dump(f);
  649.         else
  650.             return nil,err;
  651.         end
  652.     end
  653.     return lbc.chunkToBytemap(str,s);
  654. end
  655. lbc.emptyBytemap=function()
  656.     return lbc.chunkToBytemap(function()end);
  657. end
  658.  
  659. --Chunk writer
  660. local function writeByte(s,b)
  661.     s.out[s.count]=b;
  662.     s.count=s.count+1;
  663. end
  664. local function writeInt(s,i)
  665.     if s.bigEndian then
  666.         for j=0,s.intSize-1 do
  667.             s.out[s.count+j]=bit32.band(bit32.rshift(i,(s.intSize-j-1)*8),0xFF);
  668.         end
  669.     else
  670.         for j=0,s.intSize-1 do
  671.             s.out[s.count+j]=bit32.band(bit32.rshift(i,j*8),0xFF);
  672.         end
  673.     end
  674.     s.count=s.count+s.intSize;
  675. end
  676. local function writeSizet(s,i)
  677.     if s.bigEndian then
  678.         for j=0,s.sizetSize-1 do
  679.             s.out[s.count+j]=bit32.band(bit32.rshift(i,(s.sizetSize-j-1)*8),0xFF);
  680.         end
  681.     else
  682.         for j=0,s.sizetSize-1 do
  683.             s.out[s.count+j]=bit32.band(bit32.rshift(i,j*8),0xFF);
  684.         end
  685.     end
  686.     s.count=s.count+s.sizetSize;
  687. end
  688. local function writeString(s,str)
  689.     if str then writeSizet(s,#str+1);   --Write string length
  690.     else return writeSizet(s,0); end    --Write 0 (a nonexistent string)
  691.     local sb={str:byte(1,-1)};
  692.     sb[#sb+1]=0;    --Add null terminator
  693.     for i=0,#str do
  694.         s.out[s.count+i]=sb[i+1];
  695.     end
  696.     s.count=s.count+#sb;
  697. end
  698. local function writeDouble(s,x) --DOESN'T SUPPORT DENORMALIZED
  699.     local bytes={};
  700.     if x~=x then bytes[1]=0x7F;bytes[2]=0xFF;bytes[3]=0xFF;bytes[4]=0xFF;bytes[5]=0xFF;bytes[6]=0xFF;bytes[7]=0xFF;bytes[8]=0xFF;
  701.     elseif x==math.huge then bytes[1]=0x7F;bytes[2]=0xF0;bytes[3]=0x00;bytes[4]=0x00;bytes[5]=0x00;bytes[6]=0x00;bytes[7]=0x00;bytes[8]=0x00;
  702.     elseif x==-math.huge then bytes[1]=0xFF;bytes[2]=0xF0;bytes[3]=0x00;bytes[4]=0x00;bytes[5]=0x00;bytes[6]=0x00;bytes[7]=0x00;bytes[8]=0x00;
  703.     else
  704.         --Double encoder taken from ChunkSpy's convert_to["double"] and modified
  705.         --ChunkSpy Copyright (c) 2004-2006 Kein-Hong Man <[email protected]>
  706.         --http://luaforge.net/projects/chunkspy/
  707.         --http://www.geocities.com/keinhong/chunkspy.html
  708.         --Takes a normalized number and outputs an 8-byte little-endian IEEE 754 binary64 byte list
  709.         local function grab_byte(v)
  710.             return math.floor(v / 256), math.floor(v) % 256
  711.         end
  712.         local sign = 0
  713.         if x < 0 then sign = 1; x = -x end
  714.         local mantissa, exponent = math.frexp(x)
  715.         if x == 0 then -- zero
  716.             mantissa, exponent = 0, 0
  717.         else
  718.             mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
  719.             exponent = exponent + 1022
  720.         end
  721.         local byte -- convert to bytes
  722.         x = mantissa
  723.         for i = 1,6 do
  724.             x, byte = grab_byte(x); bytes[i] = byte -- 47:0
  725.         end
  726.         x, byte = grab_byte(exponent * 16 + x); bytes[7]=byte -- 55:48
  727.         x, byte = grab_byte(sign * 128 + x); bytes[8]=byte -- 63:56
  728.     end
  729.     if s.bigEndian then
  730.         for i=0,7 do
  731.             s.out[s.count+i]=bytes[8-i];
  732.         end
  733.     else
  734.         for i=0,7 do
  735.             s.out[s.count+i]=bytes[i+1];
  736.         end
  737.     end
  738.     s.count=s.count+8;
  739. end
  740. lbc.typeToRaw=function(vtype,val)
  741.     if vtype==nil or val==nil then return val; end
  742.     if vtype=="table" then
  743.         return val[1];
  744.     elseif vtype=="bytefloat" then
  745.         return lbc.fromBytefloat(val);
  746.     elseif vtype=="argamount" then
  747.         if val=="varargs" then return 0;
  748.         else return val-1; end
  749.     elseif vtype=="boolean" then
  750.         if val then return 1;
  751.         else return 0; end
  752.     end
  753. end
  754. local function writeInstruction(s,op)
  755.     local name=op.name;
  756.     local a=lbc.typeToRaw(op.typeA,op.a) or 0;
  757.     local b=lbc.typeToRaw(op.typeB,op.b) or 0;
  758.     local c=lbc.typeToRaw(op.typeC,op.c) or 0;
  759.     local code;
  760.     if name=="setlist_c" then
  761.         code=c;
  762.     else
  763.         local opcode=lbc.codes[name];
  764.         code=opcode;
  765.         code=code+a*2^6;    --Shift 6 to the left
  766.         local optype=lbc.types[opcode];
  767.         if optype==lbc.types.ABC then
  768.             code=code+c*2^14;   --Shift 14 to the left
  769.             code=code+b*2^23;   --Shift 23 to the left
  770.         else
  771.             if optype==lbc.types.AsBx then b=b+0x1FFFF; --Apply bias
  772.             elseif optype~=lbc.types.ABx then
  773.                 error("Invalid opcode "..tostring(name));
  774.             end
  775.             code=code+b*2^14;   --Shift 14 to the left
  776.         end
  777.     end
  778.     if s.bigEndian then
  779.         for j=0,3 do
  780.             local tmp=(code/2^((3-j)*8))%0x100; --rshift code by (3-j)*8 bits and band by 0xFF
  781.             s.out[s.count+j]=tmp-(tmp%1);   --Floor result and assign
  782.         end
  783.     else
  784.         for j=0,3 do
  785.             local tmp=(code/2^(j*8))%0x100;     --rshift code by j*8 bits and band by 0xFF
  786.             s.out[s.count+j]=tmp-(tmp%1);   --Floor result and assign
  787.         end
  788.     end
  789.     s.count=s.count+4;
  790. end
  791.  
  792. local function writeFunc(s,bm)
  793.     --Write function header
  794.     writeString(s,bm.header.sourceName);
  795.     writeInt(s,bm.header.firstLine);
  796.     writeInt(s,bm.header.lastLine);
  797.     writeByte(s,bm.header.upvalueCount);
  798.     writeByte(s,bm.header.paramCount);
  799.     local flags=bm.header.varargFlags;
  800.     writeByte(s,(flags.hasArg and 1 or 0)+(flags.isVararg and 2 or 0)+(flags.needsArg and 4 or 0));
  801.     writeByte(s,bm.header.stackSize);
  802.  
  803.     --Write instructions
  804.     writeInt(s,#bm.code);
  805.     for i,ins in ipairs(bm.code) do
  806.         writeInstruction(s,ins);
  807.     end
  808.  
  809.     --Write constants
  810.     local kSize=bm.constants.size;
  811.     writeInt(s,kSize);
  812.     local k;
  813.     local kType;
  814.     for i=1,kSize do
  815.         k=bm.constants[i];
  816.         kType=type(k);
  817.         if kType=="nil" then
  818.             writeByte(s,0);
  819.         elseif kType=="boolean" then
  820.             writeByte(s,1);
  821.             writeByte(s,k and 1 or 0);
  822.         elseif kType=="number" then
  823.             writeByte(s,3);
  824.             writeDouble(s,k);
  825.         elseif kType=="string" then
  826.             writeByte(s,4);
  827.             writeString(s,k);
  828.         end
  829.     end
  830.  
  831.     --Write functions
  832.     writeInt(s,#bm.functions);
  833.     for i=1,#bm.functions do
  834.         writeFunc(s,bm.functions[i]);
  835.     end
  836.  
  837.     --Write source lines
  838.     writeInt(s,#bm.sourceLines);
  839.     for i=1,#bm.sourceLines do
  840.         writeInt(s,bm.sourceLines[i]);
  841.     end
  842.  
  843.     --Write local variables
  844.     writeInt(s,#bm.localVars);
  845.     for i=1,#bm.localVars do
  846.         local lv=bm.localVars[i];
  847.         writeString(s,lv.name);
  848.         writeInt(s,lv.startScope);
  849.         writeInt(s,lv.endScope);
  850.     end
  851.  
  852.     --Write upvalues
  853.     writeInt(s,#bm.upvalues);
  854.     for i=1,#bm.upvalues do
  855.         writeString(s,bm.upvalues[i]);
  856.     end
  857. end
  858.  
  859. lbc.bytemapToChunk=function(bm,s)
  860.     s=s or {};
  861.     do
  862.         --Compute endianness
  863.         local be=s.bigEndian~=nil;
  864.         local le=s.littleEndian~=nil;
  865.         local e=s.endianness~=nil;
  866.         if (be and le) or (be and e) or (le and e) then error("Multiple endianness specifiers"); end
  867.         if le then s.bigEndian=not s.littleEndian;
  868.         elseif e then
  869.             if s.endianness=="big" then s.bigEndian=true;
  870.             elseif s.endianness=="little" then s.bigEndian=false;
  871.             else error("Invalid endianness. Must be 'big' or 'little'"); end
  872.         end
  873.     end
  874.     if s.bigEndian==nil or s.intSize==nil or s.sizetSize==nil then
  875.         local dump=string.dump(function()end);  --Get platform parameters
  876.         if s.bigEndian==nil then s.bigEndian=dump:sub(7,7)=="\0"; end
  877.         if s.intSize==nil then s.intSize=dump:sub(8,8):byte(); end
  878.         if s.sizetSize==nil then s.sizetSize=dump:sub(9,9):byte(); end
  879.     end
  880.     s.out=s.out or {};
  881.     s.count=s.count or #s.out+1;
  882.     if bm.chunkHeader.luaVersionCode~=0x51 then error("Only Lua 5.1 bytemaps are supported");
  883.     elseif bm.chunkHeader.parserVersion~=1 then error("Only parser version 1 bytemaps are supported");
  884.     elseif bm.chunkHeader.format~="official" then error("Only official bytemaps are supported");
  885.     --elseif bm.chunkHeader.instructionSize~=4 then error("Only 32-bit instruction size is supported"); --Bytemap format doesn't care, only chunks care
  886.     --elseif bm.chunkHeader.numberSize~=8 or bm.chunkHeader.numberType~="floating_point" then error("Only 64-bit double numbers are supported");    --Bytemap doesn't care, only chunks care
  887.     end
  888.     --Write chunk header
  889.     s.out[s.count]=0x1B;
  890.     s.out[s.count+1]=0x4C;
  891.     s.out[s.count+2]=0x75;
  892.     s.out[s.count+3]=0x61;
  893.     s.out[s.count+4]=bm.chunkHeader.luaVersionCode;
  894.     s.out[s.count+5]=bm.chunkHeader.formatNumber;
  895.     s.out[s.count+6]=s.bigEndian and 0 or 1;
  896.     s.out[s.count+7]=s.intSize;
  897.     s.out[s.count+8]=s.sizetSize;
  898.     s.out[s.count+9]=4;
  899.     s.out[s.count+10]=8;
  900.     s.out[s.count+11]=0;
  901.     s.count=s.count+12;
  902.     --Write main function
  903.     writeFunc(s,bm);
  904.     return s.out;
  905. end
  906. lbc.bytemapToFunction=function(bm,s)
  907.     return loadstring(string.char(unpack(lbc.bytemapToChunk(bm,s))),bm.header.sourceName or nil);
  908. end
  909. lbc.runBytemap=function(bm,...)
  910.     local f,err=lbc.bytemapToFunction(bm);
  911.     if f then
  912.         return f(...);
  913.     else
  914.         return error(err);
  915.     end
  916. end
  917.  
  918. if fs then
  919.     --CC Helper functions
  920.     lbc.fileToBytemap=function(path,s)
  921.         local h=fs.open(path,"rb");
  922.         path=fs.getName(path);
  923.         if h==nil then error("Error opening file '"..path.."'",2); end
  924.         local bytes={};
  925.         while true do
  926.             local b=h.read();
  927.             if b==nil then break; end
  928.             bytes[#bytes+1]=b;
  929.         end
  930.         h.close();
  931.         local chunk;
  932.         if bytes[1]==0x1B and bytes[2]==0x4C and bytes[3]==0x75 and bytes[4]==0x61 then
  933.             chunk=bytes;
  934.         else
  935.             --Compile and error-check
  936.             local f,err=loadstring(string.char(unpack(bytes)),path);
  937.             if not f then
  938.                 --Try to remove "lbc_parse:??:"
  939.                 local c1=err:find(":");
  940.                 if c1 then
  941.                     local c2=err:find(":",c1+1);
  942.                     if c2 then
  943.                         err=err:sub(c2+2);
  944.                     end
  945.                 end
  946.                 error(err,0);
  947.             end
  948.             --Convert into bytestring
  949.             chunk=string.dump(f);
  950.         end
  951.         return lbc.chunkToBytemap(chunk,s);
  952.     end
  953.     lbc.bytemapToFile=function(path,bm,s)
  954.         local bytes=lbc.bytemapToChunk(bm,s);
  955.         local h=fs.open(path,"wb");
  956.         path=fs.getName(path);
  957.         if h==nil then error("Could not open file "..path); end
  958.         for i=1,#bytes do
  959.             h.write(bytes[i]);
  960.         end
  961.         h.close();
  962.     end
  963. end
  964.  
  965. return lbc;
Advertisement
Add Comment
Please, Sign In to add comment