├── README.md ├── gluac ├── gluac.exe ├── lua_shared.dll ├── tier0.dll └── vstdlib.dll ├── jit ├── bc.lua ├── bcsave.lua ├── dis_arm.lua ├── dis_mips.lua ├── dis_mipsel.lua ├── dis_ppc.lua ├── dis_x64.lua ├── dis_x86.lua ├── dump.lua ├── v.lua └── vmdef.lua ├── libs ├── bcread.lua ├── bit.lua └── dis_bc.lua ├── lua51.dll ├── luajit.exe └── main.lua /README.md: -------------------------------------------------------------------------------- 1 | # THERE ARE PROBLEMS WITH UPVALUES 2 | I don't fully understand luajit bytecode, so using upvalues is broken :X Make a PR if you have a fix for this [function](https://github.com/Srlion/lua_obfuscator/blob/41d683e75c9f3a8843acb2909572a94dc5903873/main.lua#L711)! 3 | # glua_obfuscator 4 | This is more like a bytecode converter: lua code -> gluajit bytecode -> lua code 5 | 6 | There are lots of stuff that is taken from many sources that I can't remember because this was just a private thing that I was working on. 7 | 8 | How to use: 9 | luajit main.lua INPUTFILE OUTPUTFILE (Optional)USE_UTF8 10 | 11 | Credits: 12 | 13 | * [Lapin](https://github.com/ExtReMLapin) for libs/dis_bc.lua 14 | * https://github.com/everyday-as/gluac 15 | 16 | You can tell me if you find a part of code that is used from someone so I can give them credits. 17 | -------------------------------------------------------------------------------- /gluac/gluac.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/gluac/gluac.exe -------------------------------------------------------------------------------- /gluac/lua_shared.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/gluac/lua_shared.dll -------------------------------------------------------------------------------- /gluac/tier0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/gluac/tier0.dll -------------------------------------------------------------------------------- /gluac/vstdlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/gluac/vstdlib.dll -------------------------------------------------------------------------------- /jit/bc.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT bytecode listing module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module lists the bytecode of a Lua function. If it's loaded by -jbc 9 | -- it hooks into the parser and lists all functions of a chunk as they 10 | -- are parsed. 11 | -- 12 | -- Example usage: 13 | -- 14 | -- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)' 15 | -- luajit -jbc=- foo.lua 16 | -- luajit -jbc=foo.list foo.lua 17 | -- 18 | -- Default output is to stderr. To redirect the output to a file, pass a 19 | -- filename as an argument (use '-' for stdout) or set the environment 20 | -- variable LUAJIT_LISTFILE. The file is overwritten every time the module 21 | -- is started. 22 | -- 23 | -- This module can also be used programmatically: 24 | -- 25 | -- local bc = require("jit.bc") 26 | -- 27 | -- local function foo() print("hello") end 28 | -- 29 | -- bc.dump(foo) --> -- BYTECODE -- [...] 30 | -- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" 31 | -- 32 | -- local out = { 33 | -- -- Do something with each line: 34 | -- write = function(t, ...) io.write(...) end, 35 | -- close = function(t) end, 36 | -- flush = function(t) end, 37 | -- } 38 | -- bc.dump(foo, out) 39 | -- 40 | ------------------------------------------------------------------------------ 41 | -- Cache some library functions and objects. 42 | local jit = require("jit") 43 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 44 | local jutil = require("jit.util") 45 | local vmdef = require("jit.vmdef") 46 | local bit = require("bit") 47 | local sub, gsub, format = string.sub, string.gsub, string.format 48 | local byte, band, shr = string.byte, bit.band, bit.rshift 49 | local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck 50 | local funcuvname = jutil.funcuvname 51 | local bcnames = vmdef.bcnames 52 | local stdout, stderr = io.stdout, io.stderr 53 | ------------------------------------------------------------------------------ 54 | 55 | local function ctlsub(c) 56 | if c == "\n" then 57 | return "\\n" 58 | elseif c == "\r" then 59 | return "\\r" 60 | elseif c == "\t" then 61 | return "\\t" 62 | else 63 | return format("\\%03d", byte(c)) 64 | end 65 | end 66 | 67 | -- Return one bytecode line. 68 | local function bcline(func, pc, prefix) 69 | local ins, m = funcbc(func, pc) 70 | if not ins then return end 71 | local ma, mb, mc = band(m, 7), band(m, 15 * 8), band(m, 15 * 128) 72 | local a = band(shr(ins, 8), 0xff) 73 | local oidx = 6 * band(ins, 0xff) 74 | local op = sub(bcnames, oidx + 1, oidx + 6) 75 | local s = format("%04d %s %-6s %3s ", pc, (prefix and "->>") or " ", op, ma == 0 and "" or a) 76 | local d = shr(ins, 16) 77 | if mc == 13 * 128 then return format("%s=> %04d\n", s, pc + d - 0x7fff) end -- BCMjump 78 | 79 | if mb ~= 0 then 80 | d = band(d, 0xff) 81 | elseif mc == 0 then 82 | return s .. "\n" 83 | end 84 | 85 | local kc 86 | 87 | -- BCMstr 88 | if mc == 10 * 128 then 89 | kc = funck(func, -d - 1) 90 | kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub)) 91 | elseif mc == 9 * 128 then 92 | -- BCMnum 93 | kc = funck(func, d) 94 | 95 | if op == "TSETM " then 96 | kc = kc - 2 ^ 52 97 | end 98 | elseif mc == 12 * 128 then 99 | -- BCMfunc 100 | local fi = funcinfo(funck(func, -d - 1)) 101 | 102 | if fi.ffid then 103 | kc = vmdef.ffnames[fi.ffid] 104 | else 105 | kc = fi.loc 106 | end 107 | elseif mc == 5 * 128 then 108 | -- BCMuv 109 | kc = funcuvname(func, d) 110 | end 111 | 112 | -- BCMuv 113 | if ma == 5 then 114 | local ka = funcuvname(func, a) 115 | 116 | if kc then 117 | kc = ka .. " ; " .. kc 118 | else 119 | kc = ka 120 | end 121 | end 122 | 123 | if mb ~= 0 then 124 | local b = shr(ins, 24) 125 | if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end 126 | 127 | return format("%s%3d %3d\n", s, b, d) 128 | end 129 | 130 | if kc then 131 | return format("%s%3d ; %s\n", s, d, kc) 132 | end 133 | 134 | -- BCMlits 135 | if mc == 7 * 128 and d > 32767 then 136 | d = d - 65536 137 | end 138 | 139 | return format("%s%3d\n", s, d) 140 | end 141 | 142 | -- Collect branch targets of a function. 143 | local function bctargets(func) 144 | local target = {} 145 | 146 | for pc = 1, 1000000000 do 147 | local ins, m = funcbc(func, pc) 148 | if not ins then break end 149 | 150 | if band(m, 15 * 128) == 13 * 128 then 151 | target[pc + shr(ins, 16) - 0x7fff] = true 152 | end 153 | end 154 | 155 | return target 156 | end 157 | 158 | -- Dump bytecode instructions of a function. 159 | local function bcdump(func, out, all) 160 | if not out then 161 | out = stdout 162 | end 163 | 164 | local fi = funcinfo(func) 165 | 166 | if true then 167 | for n = -1, -1000000000, -1 do 168 | local k = funck(func, n) 169 | if not k then break end 170 | 171 | if type(k) == "proto" then 172 | bcdump(k, out, true) 173 | end 174 | end 175 | end 176 | 177 | out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) 178 | local target = bctargets(func) 179 | 180 | for pc = 1, 1000000000 do 181 | local s = bcline(func, pc, target[pc] and "=>") 182 | if not s then break end 183 | out:write(s) 184 | end 185 | 186 | out:write("\n") 187 | out:flush() 188 | end 189 | 190 | ------------------------------------------------------------------------------ 191 | -- Active flag and output file handle. 192 | local active, out 193 | 194 | -- List handler. 195 | local function h_list(func) 196 | return bcdump(func, out) 197 | end 198 | 199 | -- Detach list handler. 200 | local function bclistoff() 201 | if active then 202 | active = false 203 | jit.attach(h_list) 204 | 205 | if out and out ~= stdout and out ~= stderr then 206 | out:close() 207 | end 208 | 209 | out = nil 210 | end 211 | end 212 | 213 | -- Open the output file and attach list handler. 214 | local function bcliston(outfile) 215 | if active then 216 | bclistoff() 217 | end 218 | 219 | if not outfile then 220 | outfile = os.getenv("LUAJIT_LISTFILE") 221 | end 222 | 223 | if outfile then 224 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) 225 | else 226 | out = stderr 227 | end 228 | 229 | jit.attach(h_list, "bc") 230 | active = true 231 | end 232 | 233 | -- Public module functions. 234 | module(...) 235 | line = bcline 236 | dump = bcdump 237 | targets = bctargets 238 | on = bcliston 239 | off = bclistoff 240 | start = bcliston -- For -j command line option. -------------------------------------------------------------------------------- /jit/bcsave.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT module to save/list bytecode. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module saves or lists the bytecode for an input file. 9 | -- It's run by the -b command line option. 10 | -- 11 | ------------------------------------------------------------------------------ 12 | 13 | local jit = require("jit") 14 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 15 | local bit = require("bit") 16 | 17 | -- Symbol name prefix for LuaJIT bytecode. 18 | local LJBC_PREFIX = "luaJIT_BC_" 19 | 20 | ------------------------------------------------------------------------------ 21 | 22 | local function usage() 23 | io.stderr:write[[ 24 | Save LuaJIT bytecode: luajit -b[options] input output 25 | -l Only list bytecode. 26 | -s Strip debug info (default). 27 | -g Keep debug info. 28 | -n name Set module name (default: auto-detect from input name). 29 | -t type Set output file type (default: auto-detect from output name). 30 | -a arch Override architecture for object files (default: native). 31 | -o os Override OS for object files (default: native). 32 | -e chunk Use chunk string as input. 33 | -- Stop handling options. 34 | - Use stdin as input and/or stdout as output. 35 | 36 | File types: c h obj o raw (default) 37 | ]] 38 | os.exit(1) 39 | end 40 | 41 | local function check(ok, ...) 42 | if ok then return ok, ... end 43 | io.stderr:write("luajit: ", ...) 44 | io.stderr:write("\n") 45 | os.exit(1) 46 | end 47 | 48 | local function readfile(input) 49 | if type(input) == "function" then return input end 50 | if input == "-" then input = nil end 51 | return check(loadfile(input)) 52 | end 53 | 54 | local function savefile(name, mode) 55 | if name == "-" then return io.stdout end 56 | return check(io.open(name, mode)) 57 | end 58 | 59 | ------------------------------------------------------------------------------ 60 | 61 | local map_type = { 62 | raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", 63 | } 64 | 65 | local map_arch = { 66 | x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, 67 | mips = true, mipsel = true, 68 | } 69 | 70 | local map_os = { 71 | linux = true, windows = true, osx = true, freebsd = true, netbsd = true, 72 | openbsd = true, dragonfly = true, solaris = true, 73 | } 74 | 75 | local function checkarg(str, map, err) 76 | str = string.lower(str) 77 | local s = check(map[str], "unknown ", err) 78 | return s == true and str or s 79 | end 80 | 81 | local function detecttype(str) 82 | local ext = string.match(string.lower(str), "%.(%a+)$") 83 | return map_type[ext] or "raw" 84 | end 85 | 86 | local function checkmodname(str) 87 | check(string.match(str, "^[%w_.%-]+$"), "bad module name") 88 | return string.gsub(str, "[%.%-]", "_") 89 | end 90 | 91 | local function detectmodname(str) 92 | if type(str) == "string" then 93 | local tail = string.match(str, "[^/\\]+$") 94 | if tail then str = tail end 95 | local head = string.match(str, "^(.*)%.[^.]*$") 96 | if head then str = head end 97 | str = string.match(str, "^[%w_.%-]+") 98 | else 99 | str = nil 100 | end 101 | check(str, "cannot derive module name, use -n name") 102 | return string.gsub(str, "[%.%-]", "_") 103 | end 104 | 105 | ------------------------------------------------------------------------------ 106 | 107 | local function bcsave_tail(fp, output, s) 108 | local ok, err = fp:write(s) 109 | if ok and output ~= "-" then ok, err = fp:close() end 110 | check(ok, "cannot write ", output, ": ", err) 111 | end 112 | 113 | local function bcsave_raw(output, s) 114 | local fp = savefile(output, "wb") 115 | bcsave_tail(fp, output, s) 116 | end 117 | 118 | local function bcsave_c(ctx, output, s) 119 | local fp = savefile(output, "w") 120 | if ctx.type == "c" then 121 | fp:write(string.format([[ 122 | #ifdef _cplusplus 123 | extern "C" 124 | #endif 125 | #ifdef _WIN32 126 | __declspec(dllexport) 127 | #endif 128 | const char %s%s[] = { 129 | ]], LJBC_PREFIX, ctx.modname)) 130 | else 131 | fp:write(string.format([[ 132 | #define %s%s_SIZE %d 133 | static const char %s%s[] = { 134 | ]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) 135 | end 136 | local t, n, m = {}, 0, 0 137 | for i=1,#s do 138 | local b = tostring(string.byte(s, i)) 139 | m = m + #b + 1 140 | if m > 78 then 141 | fp:write(table.concat(t, ",", 1, n), ",\n") 142 | n, m = 0, #b + 1 143 | end 144 | n = n + 1 145 | t[n] = b 146 | end 147 | bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") 148 | end 149 | 150 | local function bcsave_elfobj(ctx, output, s, ffi) 151 | ffi.cdef[[ 152 | typedef struct { 153 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; 154 | uint16_t type, machine; 155 | uint32_t version; 156 | uint32_t entry, phofs, shofs; 157 | uint32_t flags; 158 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; 159 | } ELF32header; 160 | typedef struct { 161 | uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; 162 | uint16_t type, machine; 163 | uint32_t version; 164 | uint64_t entry, phofs, shofs; 165 | uint32_t flags; 166 | uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; 167 | } ELF64header; 168 | typedef struct { 169 | uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; 170 | } ELF32sectheader; 171 | typedef struct { 172 | uint32_t name, type; 173 | uint64_t flags, addr, ofs, size; 174 | uint32_t link, info; 175 | uint64_t align, entsize; 176 | } ELF64sectheader; 177 | typedef struct { 178 | uint32_t name, value, size; 179 | uint8_t info, other; 180 | uint16_t sectidx; 181 | } ELF32symbol; 182 | typedef struct { 183 | uint32_t name; 184 | uint8_t info, other; 185 | uint16_t sectidx; 186 | uint64_t value, size; 187 | } ELF64symbol; 188 | typedef struct { 189 | ELF32header hdr; 190 | ELF32sectheader sect[6]; 191 | ELF32symbol sym[2]; 192 | uint8_t space[4096]; 193 | } ELF32obj; 194 | typedef struct { 195 | ELF64header hdr; 196 | ELF64sectheader sect[6]; 197 | ELF64symbol sym[2]; 198 | uint8_t space[4096]; 199 | } ELF64obj; 200 | ]] 201 | local symname = LJBC_PREFIX..ctx.modname 202 | local is64, isbe = false, false 203 | if ctx.arch == "x64" then 204 | is64 = true 205 | elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then 206 | isbe = true 207 | end 208 | 209 | -- Handle different host/target endianess. 210 | local function f32(x) return x end 211 | local f16, fofs = f32, f32 212 | if ffi.abi("be") ~= isbe then 213 | f32 = bit.bswap 214 | function f16(x) return bit.rshift(bit.bswap(x), 16) end 215 | if is64 then 216 | local two32 = ffi.cast("int64_t", 2^32) 217 | function fofs(x) return bit.bswap(x)*two32 end 218 | else 219 | fofs = f32 220 | end 221 | end 222 | 223 | -- Create ELF object and fill in header. 224 | local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") 225 | local hdr = o.hdr 226 | if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. 227 | local bf = assert(io.open("/bin/ls", "rb")) 228 | local bs = bf:read(9) 229 | bf:close() 230 | ffi.copy(o, bs, 9) 231 | check(hdr.emagic[0] == 127, "no support for writing native object files") 232 | else 233 | hdr.emagic = "\127ELF" 234 | hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 235 | end 236 | hdr.eclass = is64 and 2 or 1 237 | hdr.eendian = isbe and 2 or 1 238 | hdr.eversion = 1 239 | hdr.type = f16(1) 240 | hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) 241 | if ctx.arch == "mips" or ctx.arch == "mipsel" then 242 | hdr.flags = 0x50001006 243 | end 244 | hdr.version = f32(1) 245 | hdr.shofs = fofs(ffi.offsetof(o, "sect")) 246 | hdr.ehsize = f16(ffi.sizeof(hdr)) 247 | hdr.shentsize = f16(ffi.sizeof(o.sect[0])) 248 | hdr.shnum = f16(6) 249 | hdr.shstridx = f16(2) 250 | 251 | -- Fill in sections and symbols. 252 | local sofs, ofs = ffi.offsetof(o, "space"), 1 253 | for i,name in ipairs{ 254 | ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", 255 | } do 256 | local sect = o.sect[i] 257 | sect.align = fofs(1) 258 | sect.name = f32(ofs) 259 | ffi.copy(o.space+ofs, name) 260 | ofs = ofs + #name+1 261 | end 262 | o.sect[1].type = f32(2) -- .symtab 263 | o.sect[1].link = f32(3) 264 | o.sect[1].info = f32(1) 265 | o.sect[1].align = fofs(8) 266 | o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) 267 | o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) 268 | o.sect[1].size = fofs(ffi.sizeof(o.sym)) 269 | o.sym[1].name = f32(1) 270 | o.sym[1].sectidx = f16(4) 271 | o.sym[1].size = fofs(#s) 272 | o.sym[1].info = 17 273 | o.sect[2].type = f32(3) -- .shstrtab 274 | o.sect[2].ofs = fofs(sofs) 275 | o.sect[2].size = fofs(ofs) 276 | o.sect[3].type = f32(3) -- .strtab 277 | o.sect[3].ofs = fofs(sofs + ofs) 278 | o.sect[3].size = fofs(#symname+1) 279 | ffi.copy(o.space+ofs+1, symname) 280 | ofs = ofs + #symname + 2 281 | o.sect[4].type = f32(1) -- .rodata 282 | o.sect[4].flags = fofs(2) 283 | o.sect[4].ofs = fofs(sofs + ofs) 284 | o.sect[4].size = fofs(#s) 285 | o.sect[5].type = f32(1) -- .note.GNU-stack 286 | o.sect[5].ofs = fofs(sofs + ofs + #s) 287 | 288 | -- Write ELF object file. 289 | local fp = savefile(output, "wb") 290 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) 291 | bcsave_tail(fp, output, s) 292 | end 293 | 294 | local function bcsave_peobj(ctx, output, s, ffi) 295 | ffi.cdef[[ 296 | typedef struct { 297 | uint16_t arch, nsects; 298 | uint32_t time, symtabofs, nsyms; 299 | uint16_t opthdrsz, flags; 300 | } PEheader; 301 | typedef struct { 302 | char name[8]; 303 | uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; 304 | uint16_t nreloc, nline; 305 | uint32_t flags; 306 | } PEsection; 307 | typedef struct __attribute((packed)) { 308 | union { 309 | char name[8]; 310 | uint32_t nameref[2]; 311 | }; 312 | uint32_t value; 313 | int16_t sect; 314 | uint16_t type; 315 | uint8_t scl, naux; 316 | } PEsym; 317 | typedef struct __attribute((packed)) { 318 | uint32_t size; 319 | uint16_t nreloc, nline; 320 | uint32_t cksum; 321 | uint16_t assoc; 322 | uint8_t comdatsel, unused[3]; 323 | } PEsymaux; 324 | typedef struct { 325 | PEheader hdr; 326 | PEsection sect[2]; 327 | // Must be an even number of symbol structs. 328 | PEsym sym0; 329 | PEsymaux sym0aux; 330 | PEsym sym1; 331 | PEsymaux sym1aux; 332 | PEsym sym2; 333 | PEsym sym3; 334 | uint32_t strtabsize; 335 | uint8_t space[4096]; 336 | } PEobj; 337 | ]] 338 | local symname = LJBC_PREFIX..ctx.modname 339 | local is64 = false 340 | if ctx.arch == "x86" then 341 | symname = "_"..symname 342 | elseif ctx.arch == "x64" then 343 | is64 = true 344 | end 345 | local symexport = " /EXPORT:"..symname..",DATA " 346 | 347 | -- The file format is always little-endian. Swap if the host is big-endian. 348 | local function f32(x) return x end 349 | local f16 = f32 350 | if ffi.abi("be") then 351 | f32 = bit.bswap 352 | function f16(x) return bit.rshift(bit.bswap(x), 16) end 353 | end 354 | 355 | -- Create PE object and fill in header. 356 | local o = ffi.new("PEobj") 357 | local hdr = o.hdr 358 | hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) 359 | hdr.nsects = f16(2) 360 | hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) 361 | hdr.nsyms = f32(6) 362 | 363 | -- Fill in sections and symbols. 364 | o.sect[0].name = ".drectve" 365 | o.sect[0].size = f32(#symexport) 366 | o.sect[0].flags = f32(0x00100a00) 367 | o.sym0.sect = f16(1) 368 | o.sym0.scl = 3 369 | o.sym0.name = ".drectve" 370 | o.sym0.naux = 1 371 | o.sym0aux.size = f32(#symexport) 372 | o.sect[1].name = ".rdata" 373 | o.sect[1].size = f32(#s) 374 | o.sect[1].flags = f32(0x40300040) 375 | o.sym1.sect = f16(2) 376 | o.sym1.scl = 3 377 | o.sym1.name = ".rdata" 378 | o.sym1.naux = 1 379 | o.sym1aux.size = f32(#s) 380 | o.sym2.sect = f16(2) 381 | o.sym2.scl = 2 382 | o.sym2.nameref[1] = f32(4) 383 | o.sym3.sect = f16(-1) 384 | o.sym3.scl = 2 385 | o.sym3.value = f32(1) 386 | o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. 387 | ffi.copy(o.space, symname) 388 | local ofs = #symname + 1 389 | o.strtabsize = f32(ofs + 4) 390 | o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) 391 | ffi.copy(o.space + ofs, symexport) 392 | ofs = ofs + #symexport 393 | o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) 394 | 395 | -- Write PE object file. 396 | local fp = savefile(output, "wb") 397 | fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) 398 | bcsave_tail(fp, output, s) 399 | end 400 | 401 | local function bcsave_machobj(ctx, output, s, ffi) 402 | ffi.cdef[[ 403 | typedef struct 404 | { 405 | uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; 406 | } mach_header; 407 | typedef struct 408 | { 409 | mach_header; uint32_t reserved; 410 | } mach_header_64; 411 | typedef struct { 412 | uint32_t cmd, cmdsize; 413 | char segname[16]; 414 | uint32_t vmaddr, vmsize, fileoff, filesize; 415 | uint32_t maxprot, initprot, nsects, flags; 416 | } mach_segment_command; 417 | typedef struct { 418 | uint32_t cmd, cmdsize; 419 | char segname[16]; 420 | uint64_t vmaddr, vmsize, fileoff, filesize; 421 | uint32_t maxprot, initprot, nsects, flags; 422 | } mach_segment_command_64; 423 | typedef struct { 424 | char sectname[16], segname[16]; 425 | uint32_t addr, size; 426 | uint32_t offset, align, reloff, nreloc, flags; 427 | uint32_t reserved1, reserved2; 428 | } mach_section; 429 | typedef struct { 430 | char sectname[16], segname[16]; 431 | uint64_t addr, size; 432 | uint32_t offset, align, reloff, nreloc, flags; 433 | uint32_t reserved1, reserved2, reserved3; 434 | } mach_section_64; 435 | typedef struct { 436 | uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; 437 | } mach_symtab_command; 438 | typedef struct { 439 | int32_t strx; 440 | uint8_t type, sect; 441 | int16_t desc; 442 | uint32_t value; 443 | } mach_nlist; 444 | typedef struct { 445 | uint32_t strx; 446 | uint8_t type, sect; 447 | uint16_t desc; 448 | uint64_t value; 449 | } mach_nlist_64; 450 | typedef struct 451 | { 452 | uint32_t magic, nfat_arch; 453 | } mach_fat_header; 454 | typedef struct 455 | { 456 | uint32_t cputype, cpusubtype, offset, size, align; 457 | } mach_fat_arch; 458 | typedef struct { 459 | struct { 460 | mach_header hdr; 461 | mach_segment_command seg; 462 | mach_section sec; 463 | mach_symtab_command sym; 464 | } arch[1]; 465 | mach_nlist sym_entry; 466 | uint8_t space[4096]; 467 | } mach_obj; 468 | typedef struct { 469 | struct { 470 | mach_header_64 hdr; 471 | mach_segment_command_64 seg; 472 | mach_section_64 sec; 473 | mach_symtab_command sym; 474 | } arch[1]; 475 | mach_nlist_64 sym_entry; 476 | uint8_t space[4096]; 477 | } mach_obj_64; 478 | typedef struct { 479 | mach_fat_header fat; 480 | mach_fat_arch fat_arch[4]; 481 | struct { 482 | mach_header hdr; 483 | mach_segment_command seg; 484 | mach_section sec; 485 | mach_symtab_command sym; 486 | } arch[4]; 487 | mach_nlist sym_entry; 488 | uint8_t space[4096]; 489 | } mach_fat_obj; 490 | ]] 491 | local symname = '_'..LJBC_PREFIX..ctx.modname 492 | local isfat, is64, align, mobj = false, false, 4, "mach_obj" 493 | if ctx.arch == "x64" then 494 | is64, align, mobj = true, 8, "mach_obj_64" 495 | elseif ctx.arch == "arm" then 496 | isfat, mobj = true, "mach_fat_obj" 497 | else 498 | check(ctx.arch == "x86", "unsupported architecture for OSX") 499 | end 500 | local function aligned(v, a) return bit.band(v+a-1, -a) end 501 | local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE. 502 | 503 | -- Create Mach-O object and fill in header. 504 | local o = ffi.new(mobj) 505 | local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) 506 | local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] 507 | local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch] 508 | if isfat then 509 | o.fat.magic = be32(0xcafebabe) 510 | o.fat.nfat_arch = be32(#cpusubtype) 511 | end 512 | 513 | -- Fill in sections and symbols. 514 | for i=0,#cpusubtype-1 do 515 | local ofs = 0 516 | if isfat then 517 | local a = o.fat_arch[i] 518 | a.cputype = be32(cputype[i+1]) 519 | a.cpusubtype = be32(cpusubtype[i+1]) 520 | -- Subsequent slices overlap each other to share data. 521 | ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) 522 | a.offset = be32(ofs) 523 | a.size = be32(mach_size-ofs+#s) 524 | end 525 | local a = o.arch[i] 526 | a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface 527 | a.hdr.cputype = cputype[i+1] 528 | a.hdr.cpusubtype = cpusubtype[i+1] 529 | a.hdr.filetype = 1 530 | a.hdr.ncmds = 2 531 | a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) 532 | a.seg.cmd = is64 and 0x19 or 0x1 533 | a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) 534 | a.seg.vmsize = #s 535 | a.seg.fileoff = mach_size-ofs 536 | a.seg.filesize = #s 537 | a.seg.maxprot = 1 538 | a.seg.initprot = 1 539 | a.seg.nsects = 1 540 | ffi.copy(a.sec.sectname, "__data") 541 | ffi.copy(a.sec.segname, "__DATA") 542 | a.sec.size = #s 543 | a.sec.offset = mach_size-ofs 544 | a.sym.cmd = 2 545 | a.sym.cmdsize = ffi.sizeof(a.sym) 546 | a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs 547 | a.sym.nsyms = 1 548 | a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs 549 | a.sym.strsize = aligned(#symname+2, align) 550 | end 551 | o.sym_entry.type = 0xf 552 | o.sym_entry.sect = 1 553 | o.sym_entry.strx = 1 554 | ffi.copy(o.space+1, symname) 555 | 556 | -- Write Macho-O object file. 557 | local fp = savefile(output, "wb") 558 | fp:write(ffi.string(o, mach_size)) 559 | bcsave_tail(fp, output, s) 560 | end 561 | 562 | local function bcsave_obj(ctx, output, s) 563 | local ok, ffi = pcall(require, "ffi") 564 | check(ok, "FFI library required to write this file type") 565 | if ctx.os == "windows" then 566 | return bcsave_peobj(ctx, output, s, ffi) 567 | elseif ctx.os == "osx" then 568 | return bcsave_machobj(ctx, output, s, ffi) 569 | else 570 | return bcsave_elfobj(ctx, output, s, ffi) 571 | end 572 | end 573 | 574 | ------------------------------------------------------------------------------ 575 | 576 | local function bclist(input, output) 577 | local f = readfile(input) 578 | require("jit.bc").dump(f, savefile(output, "w"), true) 579 | end 580 | 581 | local function bcsave(ctx, input, output) 582 | local f = readfile(input) 583 | local s = string.dump(f, ctx.strip) 584 | local t = ctx.type 585 | if not t then 586 | t = detecttype(output) 587 | ctx.type = t 588 | end 589 | if t == "raw" then 590 | bcsave_raw(output, s) 591 | else 592 | if not ctx.modname then ctx.modname = detectmodname(input) end 593 | if t == "obj" then 594 | bcsave_obj(ctx, output, s) 595 | else 596 | bcsave_c(ctx, output, s) 597 | end 598 | end 599 | end 600 | 601 | local function docmd(...) 602 | local arg = {...} 603 | local n = 1 604 | local list = false 605 | local ctx = { 606 | strip = true, arch = jit.arch, os = string.lower(jit.os), 607 | type = false, modname = false, 608 | } 609 | while n <= #arg do 610 | local a = arg[n] 611 | if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then 612 | table.remove(arg, n) 613 | if a == "--" then break end 614 | for m=2,#a do 615 | local opt = string.sub(a, m, m) 616 | if opt == "l" then 617 | list = true 618 | elseif opt == "s" then 619 | ctx.strip = true 620 | elseif opt == "g" then 621 | ctx.strip = false 622 | else 623 | if arg[n] == nil or m ~= #a then usage() end 624 | if opt == "e" then 625 | if n ~= 1 then usage() end 626 | arg[1] = check(loadstring(arg[1])) 627 | elseif opt == "n" then 628 | ctx.modname = checkmodname(table.remove(arg, n)) 629 | elseif opt == "t" then 630 | ctx.type = checkarg(table.remove(arg, n), map_type, "file type") 631 | elseif opt == "a" then 632 | ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") 633 | elseif opt == "o" then 634 | ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") 635 | else 636 | usage() 637 | end 638 | end 639 | end 640 | else 641 | n = n + 1 642 | end 643 | end 644 | if list then 645 | if #arg == 0 or #arg > 2 then usage() end 646 | bclist(arg[1], arg[2] or "-") 647 | else 648 | if #arg ~= 2 then usage() end 649 | bcsave(ctx, arg[1], arg[2]) 650 | end 651 | end 652 | 653 | ------------------------------------------------------------------------------ 654 | 655 | -- Public module functions. 656 | module(...) 657 | 658 | start = docmd -- Process -b command line option. 659 | 660 | -------------------------------------------------------------------------------- /jit/dis_arm.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT ARM disassembler module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This is a helper module used by the LuaJIT machine code dumper module. 8 | -- 9 | -- It disassembles most user-mode ARMv7 instructions 10 | -- NYI: Advanced SIMD and VFP instructions. 11 | ------------------------------------------------------------------------------ 12 | 13 | local type = type 14 | local sub, byte, format = string.sub, string.byte, string.format 15 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub 16 | local concat = table.concat 17 | local bit = require("bit") 18 | local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex 19 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 20 | 21 | ------------------------------------------------------------------------------ 22 | -- Opcode maps 23 | ------------------------------------------------------------------------------ 24 | 25 | local map_loadc = { 26 | shift = 8, mask = 15, 27 | [10] = { 28 | shift = 20, mask = 1, 29 | [0] = { 30 | shift = 23, mask = 3, 31 | [0] = "vmovFmDN", "vstmFNdr", 32 | _ = { 33 | shift = 21, mask = 1, 34 | [0] = "vstrFdl", 35 | { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", } 36 | }, 37 | }, 38 | { 39 | shift = 23, mask = 3, 40 | [0] = "vmovFDNm", 41 | { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", }, 42 | _ = { 43 | shift = 21, mask = 1, 44 | [0] = "vldrFdl", "vldmdbFNdr", 45 | }, 46 | }, 47 | }, 48 | [11] = { 49 | shift = 20, mask = 1, 50 | [0] = { 51 | shift = 23, mask = 3, 52 | [0] = "vmovGmDN", "vstmGNdr", 53 | _ = { 54 | shift = 21, mask = 1, 55 | [0] = "vstrGdl", 56 | { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", } 57 | }, 58 | }, 59 | { 60 | shift = 23, mask = 3, 61 | [0] = "vmovGDNm", 62 | { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", }, 63 | _ = { 64 | shift = 21, mask = 1, 65 | [0] = "vldrGdl", "vldmdbGNdr", 66 | }, 67 | }, 68 | }, 69 | _ = { 70 | shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc. 71 | }, 72 | } 73 | 74 | local map_vfps = { 75 | shift = 6, mask = 0x2c001, 76 | [0] = "vmlaF.dnm", "vmlsF.dnm", 77 | [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm", 78 | [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm", 79 | [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm", 80 | [0x20000] = "vdivF.dnm", 81 | [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm", 82 | [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm", 83 | [0x2c000] = "vmovF.dY", 84 | [0x2c001] = { 85 | shift = 7, mask = 0x1e01, 86 | [0] = "vmovF.dm", "vabsF.dm", 87 | [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm", 88 | [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm", 89 | [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d", 90 | [0x0e01] = "vcvtG.dF.m", 91 | [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm", 92 | [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm", 93 | [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm", 94 | }, 95 | } 96 | 97 | local map_vfpd = { 98 | shift = 6, mask = 0x2c001, 99 | [0] = "vmlaG.dnm", "vmlsG.dnm", 100 | [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm", 101 | [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm", 102 | [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm", 103 | [0x20000] = "vdivG.dnm", 104 | [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm", 105 | [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm", 106 | [0x2c000] = "vmovG.dY", 107 | [0x2c001] = { 108 | shift = 7, mask = 0x1e01, 109 | [0] = "vmovG.dm", "vabsG.dm", 110 | [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm", 111 | [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm", 112 | [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d", 113 | [0x0e01] = "vcvtF.dG.m", 114 | [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm", 115 | [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m", 116 | [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m", 117 | }, 118 | } 119 | 120 | local map_datac = { 121 | shift = 24, mask = 1, 122 | [0] = { 123 | shift = 4, mask = 1, 124 | [0] = { 125 | shift = 8, mask = 15, 126 | [10] = map_vfps, 127 | [11] = map_vfpd, 128 | -- NYI cdp, mcr, mrc. 129 | }, 130 | { 131 | shift = 8, mask = 15, 132 | [10] = { 133 | shift = 20, mask = 15, 134 | [0] = "vmovFnD", "vmovFDn", 135 | [14] = "vmsrD", 136 | [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", }, 137 | }, 138 | }, 139 | }, 140 | "svcT", 141 | } 142 | 143 | local map_loadcu = { 144 | shift = 0, mask = 0, -- NYI unconditional CP load/store. 145 | } 146 | 147 | local map_datacu = { 148 | shift = 0, mask = 0, -- NYI unconditional CP data. 149 | } 150 | 151 | local map_simddata = { 152 | shift = 0, mask = 0, -- NYI SIMD data. 153 | } 154 | 155 | local map_simdload = { 156 | shift = 0, mask = 0, -- NYI SIMD load/store, preload. 157 | } 158 | 159 | local map_preload = { 160 | shift = 0, mask = 0, -- NYI preload. 161 | } 162 | 163 | local map_media = { 164 | shift = 20, mask = 31, 165 | [0] = false, 166 | { --01 167 | shift = 5, mask = 7, 168 | [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM", 169 | "sadd8DNM", false, false, "ssub8DNM", 170 | }, 171 | { --02 172 | shift = 5, mask = 7, 173 | [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM", 174 | "qadd8DNM", false, false, "qsub8DNM", 175 | }, 176 | { --03 177 | shift = 5, mask = 7, 178 | [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM", 179 | "shadd8DNM", false, false, "shsub8DNM", 180 | }, 181 | false, 182 | { --05 183 | shift = 5, mask = 7, 184 | [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM", 185 | "uadd8DNM", false, false, "usub8DNM", 186 | }, 187 | { --06 188 | shift = 5, mask = 7, 189 | [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM", 190 | "uqadd8DNM", false, false, "uqsub8DNM", 191 | }, 192 | { --07 193 | shift = 5, mask = 7, 194 | [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM", 195 | "uhadd8DNM", false, false, "uhsub8DNM", 196 | }, 197 | { --08 198 | shift = 5, mask = 7, 199 | [0] = "pkhbtDNMU", false, "pkhtbDNMU", 200 | { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", }, 201 | "pkhbtDNMU", "selDNM", "pkhtbDNMU", 202 | }, 203 | false, 204 | { --0a 205 | shift = 5, mask = 7, 206 | [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu", 207 | { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", }, 208 | "ssatDxMu", false, "ssatDxMu", 209 | }, 210 | { --0b 211 | shift = 5, mask = 7, 212 | [0] = "ssatDxMu", "revDM", "ssatDxMu", 213 | { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", }, 214 | "ssatDxMu", "rev16DM", "ssatDxMu", 215 | }, 216 | { --0c 217 | shift = 5, mask = 7, 218 | [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", }, 219 | }, 220 | false, 221 | { --0e 222 | shift = 5, mask = 7, 223 | [0] = "usatDwMu", "usat16DwM", "usatDwMu", 224 | { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", }, 225 | "usatDwMu", false, "usatDwMu", 226 | }, 227 | { --0f 228 | shift = 5, mask = 7, 229 | [0] = "usatDwMu", "rbitDM", "usatDwMu", 230 | { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", }, 231 | "usatDwMu", "revshDM", "usatDwMu", 232 | }, 233 | { --10 234 | shift = 12, mask = 15, 235 | [15] = { 236 | shift = 5, mask = 7, 237 | "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS", 238 | }, 239 | _ = { 240 | shift = 5, mask = 7, 241 | [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD", 242 | }, 243 | }, 244 | false, false, false, 245 | { --14 246 | shift = 5, mask = 7, 247 | [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS", 248 | }, 249 | { --15 250 | shift = 5, mask = 7, 251 | [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", }, 252 | { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", }, 253 | false, false, false, false, 254 | "smmlsNMSD", "smmlsrNMSD", 255 | }, 256 | false, false, 257 | { --18 258 | shift = 5, mask = 7, 259 | [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", }, 260 | }, 261 | false, 262 | { --1a 263 | shift = 5, mask = 3, [2] = "sbfxDMvw", 264 | }, 265 | { --1b 266 | shift = 5, mask = 3, [2] = "sbfxDMvw", 267 | }, 268 | { --1c 269 | shift = 5, mask = 3, 270 | [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, 271 | }, 272 | { --1d 273 | shift = 5, mask = 3, 274 | [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, 275 | }, 276 | { --1e 277 | shift = 5, mask = 3, [2] = "ubfxDMvw", 278 | }, 279 | { --1f 280 | shift = 5, mask = 3, [2] = "ubfxDMvw", 281 | }, 282 | } 283 | 284 | local map_load = { 285 | shift = 21, mask = 9, 286 | { 287 | shift = 20, mask = 5, 288 | [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL", 289 | }, 290 | _ = { 291 | shift = 20, mask = 5, 292 | [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL", 293 | } 294 | } 295 | 296 | local map_load1 = { 297 | shift = 4, mask = 1, 298 | [0] = map_load, map_media, 299 | } 300 | 301 | local map_loadm = { 302 | shift = 20, mask = 1, 303 | [0] = { 304 | shift = 23, mask = 3, 305 | [0] = "stmdaNR", "stmNR", 306 | { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR", 307 | }, 308 | { 309 | shift = 23, mask = 3, 310 | [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", }, 311 | "ldmdbNR", "ldmibNR", 312 | }, 313 | } 314 | 315 | local map_data = { 316 | shift = 21, mask = 15, 317 | [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs", 318 | "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs", 319 | "tstNP", "teqNP", "cmpNP", "cmnNP", 320 | "orrDNPs", "movDPs", "bicDNPs", "mvnDPs", 321 | } 322 | 323 | local map_mul = { 324 | shift = 21, mask = 7, 325 | [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS", 326 | "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs", 327 | } 328 | 329 | local map_sync = { 330 | shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd. 331 | [0] = "swpDMN", false, false, false, 332 | "swpbDMN", false, false, false, 333 | "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN", 334 | "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN", 335 | } 336 | 337 | local map_mulh = { 338 | shift = 21, mask = 3, 339 | [0] = { shift = 5, mask = 3, 340 | [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", }, 341 | { shift = 5, mask = 3, 342 | [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", }, 343 | { shift = 5, mask = 3, 344 | [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", }, 345 | { shift = 5, mask = 3, 346 | [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", }, 347 | } 348 | 349 | local map_misc = { 350 | shift = 4, mask = 7, 351 | -- NYI: decode PSR bits of msr. 352 | [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", }, 353 | { shift = 21, mask = 3, "bxM", false, "clzDM", }, 354 | { shift = 21, mask = 3, "bxjM", }, 355 | { shift = 21, mask = 3, "blxM", }, 356 | false, 357 | { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", }, 358 | false, 359 | { shift = 21, mask = 3, "bkptK", }, 360 | } 361 | 362 | local map_datar = { 363 | shift = 4, mask = 9, 364 | [9] = { 365 | shift = 5, mask = 3, 366 | [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, }, 367 | { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", }, 368 | { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", }, 369 | { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", }, 370 | }, 371 | _ = { 372 | shift = 20, mask = 25, 373 | [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, }, 374 | _ = { 375 | shift = 0, mask = 0xffffffff, 376 | [bor(0xe1a00000)] = "nop", 377 | _ = map_data, 378 | } 379 | }, 380 | } 381 | 382 | local map_datai = { 383 | shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12. 384 | [16] = "movwDW", [20] = "movtDW", 385 | [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", }, 386 | [22] = "msrNW", 387 | _ = map_data, 388 | } 389 | 390 | local map_branch = { 391 | shift = 24, mask = 1, 392 | [0] = "bB", "blB" 393 | } 394 | 395 | local map_condins = { 396 | [0] = map_datar, map_datai, map_load, map_load1, 397 | map_loadm, map_branch, map_loadc, map_datac 398 | } 399 | 400 | -- NYI: setend. 401 | local map_uncondins = { 402 | [0] = false, map_simddata, map_simdload, map_preload, 403 | false, "blxB", map_loadcu, map_datacu, 404 | } 405 | 406 | ------------------------------------------------------------------------------ 407 | 408 | local map_gpr = { 409 | [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 410 | "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", 411 | } 412 | 413 | local map_cond = { 414 | [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", 415 | "hi", "ls", "ge", "lt", "gt", "le", "al", 416 | } 417 | 418 | local map_shift = { [0] = "lsl", "lsr", "asr", "ror", } 419 | 420 | ------------------------------------------------------------------------------ 421 | 422 | -- Output a nicely formatted line with an opcode and operands. 423 | local function putop(ctx, text, operands) 424 | local pos = ctx.pos 425 | local extra = "" 426 | if ctx.rel then 427 | local sym = ctx.symtab[ctx.rel] 428 | if sym then 429 | extra = "\t->"..sym 430 | elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then 431 | extra = "\t; 0x"..tohex(ctx.rel) 432 | end 433 | end 434 | if ctx.hexdump > 0 then 435 | ctx.out(format("%08x %s %-5s %s%s\n", 436 | ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) 437 | else 438 | ctx.out(format("%08x %-5s %s%s\n", 439 | ctx.addr+pos, text, concat(operands, ", "), extra)) 440 | end 441 | ctx.pos = pos + 4 442 | end 443 | 444 | -- Fallback for unknown opcodes. 445 | local function unknown(ctx) 446 | return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) 447 | end 448 | 449 | -- Format operand 2 of load/store opcodes. 450 | local function fmtload(ctx, op, pos) 451 | local base = map_gpr[band(rshift(op, 16), 15)] 452 | local x, ofs 453 | local ext = (band(op, 0x04000000) == 0) 454 | if not ext and band(op, 0x02000000) == 0 then 455 | ofs = band(op, 4095) 456 | if band(op, 0x00800000) == 0 then ofs = -ofs end 457 | if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end 458 | ofs = "#"..ofs 459 | elseif ext and band(op, 0x00400000) ~= 0 then 460 | ofs = band(op, 15) + band(rshift(op, 4), 0xf0) 461 | if band(op, 0x00800000) == 0 then ofs = -ofs end 462 | if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end 463 | ofs = "#"..ofs 464 | else 465 | ofs = map_gpr[band(op, 15)] 466 | if ext or band(op, 0xfe0) == 0 then 467 | elseif band(op, 0xfe0) == 0x60 then 468 | ofs = format("%s, rrx", ofs) 469 | else 470 | local sh = band(rshift(op, 7), 31) 471 | if sh == 0 then sh = 32 end 472 | ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh) 473 | end 474 | if band(op, 0x00800000) == 0 then ofs = "-"..ofs end 475 | end 476 | if ofs == "#0" then 477 | x = format("[%s]", base) 478 | elseif band(op, 0x01000000) == 0 then 479 | x = format("[%s], %s", base, ofs) 480 | else 481 | x = format("[%s, %s]", base, ofs) 482 | end 483 | if band(op, 0x01200000) == 0x01200000 then x = x.."!" end 484 | return x 485 | end 486 | 487 | -- Format operand 2 of vector load/store opcodes. 488 | local function fmtvload(ctx, op, pos) 489 | local base = map_gpr[band(rshift(op, 16), 15)] 490 | local ofs = band(op, 255)*4 491 | if band(op, 0x00800000) == 0 then ofs = -ofs end 492 | if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end 493 | if ofs == 0 then 494 | return format("[%s]", base) 495 | else 496 | return format("[%s, #%d]", base, ofs) 497 | end 498 | end 499 | 500 | local function fmtvr(op, vr, sh0, sh1) 501 | if vr == "s" then 502 | return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1)) 503 | else 504 | return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16)) 505 | end 506 | end 507 | 508 | -- Disassemble a single instruction. 509 | local function disass_ins(ctx) 510 | local pos = ctx.pos 511 | local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) 512 | local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) 513 | local operands = {} 514 | local suffix = "" 515 | local last, name, pat 516 | local vr 517 | ctx.op = op 518 | ctx.rel = nil 519 | 520 | local cond = rshift(op, 28) 521 | local opat 522 | if cond == 15 then 523 | opat = map_uncondins[band(rshift(op, 25), 7)] 524 | else 525 | if cond ~= 14 then suffix = map_cond[cond] end 526 | opat = map_condins[band(rshift(op, 25), 7)] 527 | end 528 | while type(opat) ~= "string" do 529 | if not opat then return unknown(ctx) end 530 | opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ 531 | end 532 | name, pat = match(opat, "^([a-z0-9]*)(.*)") 533 | if sub(pat, 1, 1) == "." then 534 | local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") 535 | suffix = suffix..s2 536 | pat = p2 537 | end 538 | 539 | for p in gmatch(pat, ".") do 540 | local x = nil 541 | if p == "D" then 542 | x = map_gpr[band(rshift(op, 12), 15)] 543 | elseif p == "N" then 544 | x = map_gpr[band(rshift(op, 16), 15)] 545 | elseif p == "S" then 546 | x = map_gpr[band(rshift(op, 8), 15)] 547 | elseif p == "M" then 548 | x = map_gpr[band(op, 15)] 549 | elseif p == "d" then 550 | x = fmtvr(op, vr, 12, 22) 551 | elseif p == "n" then 552 | x = fmtvr(op, vr, 16, 7) 553 | elseif p == "m" then 554 | x = fmtvr(op, vr, 0, 5) 555 | elseif p == "P" then 556 | if band(op, 0x02000000) ~= 0 then 557 | x = ror(band(op, 255), 2*band(rshift(op, 8), 15)) 558 | else 559 | x = map_gpr[band(op, 15)] 560 | if band(op, 0xff0) ~= 0 then 561 | operands[#operands+1] = x 562 | local s = map_shift[band(rshift(op, 5), 3)] 563 | local r = nil 564 | if band(op, 0xf90) == 0 then 565 | if s == "ror" then s = "rrx" else r = "#32" end 566 | elseif band(op, 0x10) == 0 then 567 | r = "#"..band(rshift(op, 7), 31) 568 | else 569 | r = map_gpr[band(rshift(op, 8), 15)] 570 | end 571 | if name == "mov" then name = s; x = r 572 | elseif r then x = format("%s %s", s, r) 573 | else x = s end 574 | end 575 | end 576 | elseif p == "L" then 577 | x = fmtload(ctx, op, pos) 578 | elseif p == "l" then 579 | x = fmtvload(ctx, op, pos) 580 | elseif p == "B" then 581 | local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6) 582 | if cond == 15 then addr = addr + band(rshift(op, 23), 2) end 583 | ctx.rel = addr 584 | x = "0x"..tohex(addr) 585 | elseif p == "F" then 586 | vr = "s" 587 | elseif p == "G" then 588 | vr = "d" 589 | elseif p == "." then 590 | suffix = suffix..(vr == "s" and ".f32" or ".f64") 591 | elseif p == "R" then 592 | if band(op, 0x00200000) ~= 0 and #operands == 1 then 593 | operands[1] = operands[1].."!" 594 | end 595 | local t = {} 596 | for i=0,15 do 597 | if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end 598 | end 599 | x = "{"..concat(t, ", ").."}" 600 | elseif p == "r" then 601 | if band(op, 0x00200000) ~= 0 and #operands == 2 then 602 | operands[1] = operands[1].."!" 603 | end 604 | local s = tonumber(sub(last, 2)) 605 | local n = band(op, 255) 606 | if vr == "d" then n = rshift(n, 1) end 607 | operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1) 608 | elseif p == "W" then 609 | x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000) 610 | elseif p == "T" then 611 | x = "#0x"..tohex(band(op, 0x00ffffff), 6) 612 | elseif p == "U" then 613 | x = band(rshift(op, 7), 31) 614 | if x == 0 then x = nil end 615 | elseif p == "u" then 616 | x = band(rshift(op, 7), 31) 617 | if band(op, 0x40) == 0 then 618 | if x == 0 then x = nil else x = "lsl #"..x end 619 | else 620 | if x == 0 then x = "asr #32" else x = "asr #"..x end 621 | end 622 | elseif p == "v" then 623 | x = band(rshift(op, 7), 31) 624 | elseif p == "w" then 625 | x = band(rshift(op, 16), 31) 626 | elseif p == "x" then 627 | x = band(rshift(op, 16), 31) + 1 628 | elseif p == "X" then 629 | x = band(rshift(op, 16), 31) - last + 1 630 | elseif p == "Y" then 631 | x = band(rshift(op, 12), 0xf0) + band(op, 0x0f) 632 | elseif p == "K" then 633 | x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4) 634 | elseif p == "s" then 635 | if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end 636 | else 637 | assert(false) 638 | end 639 | if x then 640 | last = x 641 | if type(x) == "number" then x = "#"..x end 642 | operands[#operands+1] = x 643 | end 644 | end 645 | 646 | return putop(ctx, name..suffix, operands) 647 | end 648 | 649 | ------------------------------------------------------------------------------ 650 | 651 | -- Disassemble a block of code. 652 | local function disass_block(ctx, ofs, len) 653 | if not ofs then ofs = 0 end 654 | local stop = len and ofs+len or #ctx.code 655 | ctx.pos = ofs 656 | ctx.rel = nil 657 | while ctx.pos < stop do disass_ins(ctx) end 658 | end 659 | 660 | -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 661 | local function create_(code, addr, out) 662 | local ctx = {} 663 | ctx.code = code 664 | ctx.addr = addr or 0 665 | ctx.out = out or io.write 666 | ctx.symtab = {} 667 | ctx.disass = disass_block 668 | ctx.hexdump = 8 669 | return ctx 670 | end 671 | 672 | -- Simple API: disassemble code (a string) at address and output via out. 673 | local function disass_(code, addr, out) 674 | create_(code, addr, out):disass() 675 | end 676 | 677 | -- Return register name for RID. 678 | local function regname_(r) 679 | if r < 16 then return map_gpr[r] end 680 | return "d"..(r-16) 681 | end 682 | 683 | -- Public module functions. 684 | module(...) 685 | 686 | create = create_ 687 | disass = disass_ 688 | regname = regname_ 689 | 690 | -------------------------------------------------------------------------------- /jit/dis_mips.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT MIPS disassembler module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT/X license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This is a helper module used by the LuaJIT machine code dumper module. 8 | -- 9 | -- It disassembles all standard MIPS32R1/R2 instructions. 10 | -- Default mode is big-endian, but see: dis_mipsel.lua 11 | ------------------------------------------------------------------------------ 12 | 13 | local type = type 14 | local sub, byte, format = string.sub, string.byte, string.format 15 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub 16 | local concat = table.concat 17 | local bit = require("bit") 18 | local band, bor, tohex = bit.band, bit.bor, bit.tohex 19 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 20 | 21 | ------------------------------------------------------------------------------ 22 | -- Primary and extended opcode maps 23 | ------------------------------------------------------------------------------ 24 | 25 | local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } 26 | local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } 27 | local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } 28 | 29 | local map_special = { 30 | shift = 0, mask = 63, 31 | [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" }, 32 | map_movci, map_srl, "sraDTA", 33 | "sllvDTS", false, map_srlv, "sravDTS", 34 | "jrS", "jalrD1S", "movzDST", "movnDST", 35 | "syscallY", "breakY", false, "sync", 36 | "mfhiD", "mthiS", "mfloD", "mtloS", 37 | false, false, false, false, 38 | "multST", "multuST", "divST", "divuST", 39 | false, false, false, false, 40 | "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T", 41 | "andDST", "orDST", "xorDST", "nor|notDST0", 42 | false, false, "sltDST", "sltuDST", 43 | false, false, false, false, 44 | "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ", 45 | "teqSTZ", false, "tneSTZ", 46 | } 47 | 48 | local map_special2 = { 49 | shift = 0, mask = 63, 50 | [0] = "maddST", "madduST", "mulDST", false, 51 | "msubST", "msubuST", 52 | [32] = "clzDS", [33] = "cloDS", 53 | [63] = "sdbbpY", 54 | } 55 | 56 | local map_bshfl = { 57 | shift = 6, mask = 31, 58 | [2] = "wsbhDT", 59 | [16] = "sebDT", 60 | [24] = "sehDT", 61 | } 62 | 63 | local map_special3 = { 64 | shift = 0, mask = 63, 65 | [0] = "extTSAK", [4] = "insTSAL", 66 | [32] = map_bshfl, 67 | [59] = "rdhwrTD", 68 | } 69 | 70 | local map_regimm = { 71 | shift = 16, mask = 31, 72 | [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB", 73 | false, false, false, false, 74 | "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI", 75 | "teqiSI", false, "tneiSI", false, 76 | "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB", 77 | false, false, false, false, 78 | false, false, false, false, 79 | false, false, false, "synciSO", 80 | } 81 | 82 | local map_cop0 = { 83 | shift = 25, mask = 1, 84 | [0] = { 85 | shift = 21, mask = 15, 86 | [0] = "mfc0TDW", [4] = "mtc0TDW", 87 | [10] = "rdpgprDT", 88 | [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", }, 89 | [14] = "wrpgprDT", 90 | }, { 91 | shift = 0, mask = 63, 92 | [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp", 93 | [24] = "eret", [31] = "deret", 94 | [32] = "wait", 95 | }, 96 | } 97 | 98 | local map_cop1s = { 99 | shift = 0, mask = 63, 100 | [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH", 101 | "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG", 102 | "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG", 103 | "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG", 104 | false, 105 | { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" }, 106 | "movz.sFGT", "movn.sFGT", 107 | false, "recip.sFG", "rsqrt.sFG", false, 108 | false, false, false, false, 109 | false, false, false, false, 110 | false, "cvt.d.sFG", false, false, 111 | "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false, 112 | false, false, false, false, 113 | false, false, false, false, 114 | "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH", 115 | "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH", 116 | "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH", 117 | "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH", 118 | } 119 | 120 | local map_cop1d = { 121 | shift = 0, mask = 63, 122 | [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH", 123 | "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG", 124 | "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG", 125 | "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG", 126 | false, 127 | { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" }, 128 | "movz.dFGT", "movn.dFGT", 129 | false, "recip.dFG", "rsqrt.dFG", false, 130 | false, false, false, false, 131 | false, false, false, false, 132 | "cvt.s.dFG", false, false, false, 133 | "cvt.w.dFG", "cvt.l.dFG", false, false, 134 | false, false, false, false, 135 | false, false, false, false, 136 | "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH", 137 | "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH", 138 | "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH", 139 | "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH", 140 | } 141 | 142 | local map_cop1ps = { 143 | shift = 0, mask = 63, 144 | [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false, 145 | false, "abs.psFG", "mov.psFG", "neg.psFG", 146 | false, false, false, false, 147 | false, false, false, false, 148 | false, 149 | { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" }, 150 | "movz.psFGT", "movn.psFGT", 151 | false, false, false, false, 152 | false, false, false, false, 153 | false, false, false, false, 154 | "cvt.s.puFG", false, false, false, 155 | false, false, false, false, 156 | "cvt.s.plFG", false, false, false, 157 | "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH", 158 | "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH", 159 | "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH", 160 | "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH", 161 | "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH", 162 | } 163 | 164 | local map_cop1w = { 165 | shift = 0, mask = 63, 166 | [32] = "cvt.s.wFG", [33] = "cvt.d.wFG", 167 | } 168 | 169 | local map_cop1l = { 170 | shift = 0, mask = 63, 171 | [32] = "cvt.s.lFG", [33] = "cvt.d.lFG", 172 | } 173 | 174 | local map_cop1bc = { 175 | shift = 16, mask = 3, 176 | [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB", 177 | } 178 | 179 | local map_cop1 = { 180 | shift = 21, mask = 31, 181 | [0] = "mfc1TG", false, "cfc1TG", "mfhc1TG", 182 | "mtc1TG", false, "ctc1TG", "mthc1TG", 183 | map_cop1bc, false, false, false, 184 | false, false, false, false, 185 | map_cop1s, map_cop1d, false, false, 186 | map_cop1w, map_cop1l, map_cop1ps, 187 | } 188 | 189 | local map_cop1x = { 190 | shift = 0, mask = 63, 191 | [0] = "lwxc1FSX", "ldxc1FSX", false, false, 192 | false, "luxc1FSX", false, false, 193 | "swxc1FSX", "sdxc1FSX", false, false, 194 | false, "suxc1FSX", false, "prefxMSX", 195 | false, false, false, false, 196 | false, false, false, false, 197 | false, false, false, false, 198 | false, false, "alnv.psFGHS", false, 199 | "madd.sFRGH", "madd.dFRGH", false, false, 200 | false, false, "madd.psFRGH", false, 201 | "msub.sFRGH", "msub.dFRGH", false, false, 202 | false, false, "msub.psFRGH", false, 203 | "nmadd.sFRGH", "nmadd.dFRGH", false, false, 204 | false, false, "nmadd.psFRGH", false, 205 | "nmsub.sFRGH", "nmsub.dFRGH", false, false, 206 | false, false, "nmsub.psFRGH", false, 207 | } 208 | 209 | local map_pri = { 210 | [0] = map_special, map_regimm, "jJ", "jalJ", 211 | "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB", 212 | "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI", 213 | "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU", 214 | map_cop0, map_cop1, false, map_cop1x, 215 | "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB", 216 | false, false, false, false, 217 | map_special2, false, false, map_special3, 218 | "lbTSO", "lhTSO", "lwlTSO", "lwTSO", 219 | "lbuTSO", "lhuTSO", "lwrTSO", false, 220 | "sbTSO", "shTSO", "swlTSO", "swTSO", 221 | false, false, "swrTSO", "cacheNSO", 222 | "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO", 223 | false, "ldc1HSO", "ldc2TSO", false, 224 | "scTSO", "swc1HSO", "swc2TSO", false, 225 | false, "sdc1HSO", "sdc2TSO", false, 226 | } 227 | 228 | ------------------------------------------------------------------------------ 229 | 230 | local map_gpr = { 231 | [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 232 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 233 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 234 | "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra", 235 | } 236 | 237 | ------------------------------------------------------------------------------ 238 | 239 | -- Output a nicely formatted line with an opcode and operands. 240 | local function putop(ctx, text, operands) 241 | local pos = ctx.pos 242 | local extra = "" 243 | if ctx.rel then 244 | local sym = ctx.symtab[ctx.rel] 245 | if sym then extra = "\t->"..sym end 246 | end 247 | if ctx.hexdump > 0 then 248 | ctx.out(format("%08x %s %-7s %s%s\n", 249 | ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) 250 | else 251 | ctx.out(format("%08x %-7s %s%s\n", 252 | ctx.addr+pos, text, concat(operands, ", "), extra)) 253 | end 254 | ctx.pos = pos + 4 255 | end 256 | 257 | -- Fallback for unknown opcodes. 258 | local function unknown(ctx) 259 | return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) 260 | end 261 | 262 | local function get_be(ctx) 263 | local pos = ctx.pos 264 | local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) 265 | return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) 266 | end 267 | 268 | local function get_le(ctx) 269 | local pos = ctx.pos 270 | local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) 271 | return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) 272 | end 273 | 274 | -- Disassemble a single instruction. 275 | local function disass_ins(ctx) 276 | local op = ctx:get() 277 | local operands = {} 278 | local last = nil 279 | ctx.op = op 280 | ctx.rel = nil 281 | 282 | local opat = map_pri[rshift(op, 26)] 283 | while type(opat) ~= "string" do 284 | if not opat then return unknown(ctx) end 285 | opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ 286 | end 287 | local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") 288 | local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") 289 | if altname then pat = pat2 end 290 | 291 | for p in gmatch(pat, ".") do 292 | local x = nil 293 | if p == "S" then 294 | x = map_gpr[band(rshift(op, 21), 31)] 295 | elseif p == "T" then 296 | x = map_gpr[band(rshift(op, 16), 31)] 297 | elseif p == "D" then 298 | x = map_gpr[band(rshift(op, 11), 31)] 299 | elseif p == "F" then 300 | x = "f"..band(rshift(op, 6), 31) 301 | elseif p == "G" then 302 | x = "f"..band(rshift(op, 11), 31) 303 | elseif p == "H" then 304 | x = "f"..band(rshift(op, 16), 31) 305 | elseif p == "R" then 306 | x = "f"..band(rshift(op, 21), 31) 307 | elseif p == "A" then 308 | x = band(rshift(op, 6), 31) 309 | elseif p == "M" then 310 | x = band(rshift(op, 11), 31) 311 | elseif p == "N" then 312 | x = band(rshift(op, 16), 31) 313 | elseif p == "C" then 314 | x = band(rshift(op, 18), 7) 315 | if x == 0 then x = nil end 316 | elseif p == "K" then 317 | x = band(rshift(op, 11), 31) + 1 318 | elseif p == "L" then 319 | x = band(rshift(op, 11), 31) - last + 1 320 | elseif p == "I" then 321 | x = arshift(lshift(op, 16), 16) 322 | elseif p == "U" then 323 | x = band(op, 0xffff) 324 | elseif p == "O" then 325 | local disp = arshift(lshift(op, 16), 16) 326 | operands[#operands] = format("%d(%s)", disp, last) 327 | elseif p == "X" then 328 | local index = map_gpr[band(rshift(op, 16), 31)] 329 | operands[#operands] = format("%s(%s)", index, last) 330 | elseif p == "B" then 331 | x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4 332 | ctx.rel = x 333 | x = "0x"..tohex(x) 334 | elseif p == "J" then 335 | x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4 336 | ctx.rel = x 337 | x = "0x"..tohex(x) 338 | elseif p == "V" then 339 | x = band(rshift(op, 8), 7) 340 | if x == 0 then x = nil end 341 | elseif p == "W" then 342 | x = band(op, 7) 343 | if x == 0 then x = nil end 344 | elseif p == "Y" then 345 | x = band(rshift(op, 6), 0x000fffff) 346 | if x == 0 then x = nil end 347 | elseif p == "Z" then 348 | x = band(rshift(op, 6), 1023) 349 | if x == 0 then x = nil end 350 | elseif p == "0" then 351 | if last == "r0" or last == 0 then 352 | local n = #operands 353 | operands[n] = nil 354 | last = operands[n-1] 355 | if altname then 356 | local a1, a2 = match(altname, "([^|]*)|(.*)") 357 | if a1 then name, altname = a1, a2 358 | else name = altname end 359 | end 360 | end 361 | elseif p == "1" then 362 | if last == "ra" then 363 | operands[#operands] = nil 364 | end 365 | else 366 | assert(false) 367 | end 368 | if x then operands[#operands+1] = x; last = x end 369 | end 370 | 371 | return putop(ctx, name, operands) 372 | end 373 | 374 | ------------------------------------------------------------------------------ 375 | 376 | -- Disassemble a block of code. 377 | local function disass_block(ctx, ofs, len) 378 | if not ofs then ofs = 0 end 379 | local stop = len and ofs+len or #ctx.code 380 | stop = stop - stop % 4 381 | ctx.pos = ofs - ofs % 4 382 | ctx.rel = nil 383 | while ctx.pos < stop do disass_ins(ctx) end 384 | end 385 | 386 | -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 387 | local function create_(code, addr, out) 388 | local ctx = {} 389 | ctx.code = code 390 | ctx.addr = addr or 0 391 | ctx.out = out or io.write 392 | ctx.symtab = {} 393 | ctx.disass = disass_block 394 | ctx.hexdump = 8 395 | ctx.get = get_be 396 | return ctx 397 | end 398 | 399 | local function create_el_(code, addr, out) 400 | local ctx = create_(code, addr, out) 401 | ctx.get = get_le 402 | return ctx 403 | end 404 | 405 | -- Simple API: disassemble code (a string) at address and output via out. 406 | local function disass_(code, addr, out) 407 | create_(code, addr, out):disass() 408 | end 409 | 410 | local function disass_el_(code, addr, out) 411 | create_el_(code, addr, out):disass() 412 | end 413 | 414 | -- Return register name for RID. 415 | local function regname_(r) 416 | if r < 32 then return map_gpr[r] end 417 | return "f"..(r-32) 418 | end 419 | 420 | -- Public module functions. 421 | module(...) 422 | 423 | create = create_ 424 | create_el = create_el_ 425 | disass = disass_ 426 | disass_el = disass_el_ 427 | regname = regname_ 428 | 429 | -------------------------------------------------------------------------------- /jit/dis_mipsel.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT MIPSEL disassembler wrapper module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This module just exports the little-endian functions from the 8 | -- MIPS disassembler module. All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | local require = require 12 | 13 | module(...) 14 | 15 | local dis_mips = require(_PACKAGE.."dis_mips") 16 | 17 | create = dis_mips.create_el 18 | disass = dis_mips.disass_el 19 | regname = dis_mips.regname 20 | 21 | -------------------------------------------------------------------------------- /jit/dis_ppc.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT PPC disassembler module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT/X license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This is a helper module used by the LuaJIT machine code dumper module. 8 | -- 9 | -- It disassembles all common, non-privileged 32/64 bit PowerPC instructions 10 | -- plus the e500 SPE instructions and some Cell/Xenon extensions. 11 | -- 12 | -- NYI: VMX, VMX128 13 | ------------------------------------------------------------------------------ 14 | 15 | local type = type 16 | local sub, byte, format = string.sub, string.byte, string.format 17 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub 18 | local concat = table.concat 19 | local bit = require("bit") 20 | local band, bor, tohex = bit.band, bit.bor, bit.tohex 21 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 22 | 23 | ------------------------------------------------------------------------------ 24 | -- Primary and extended opcode maps 25 | ------------------------------------------------------------------------------ 26 | 27 | local map_crops = { 28 | shift = 1, mask = 1023, 29 | [0] = "mcrfXX", 30 | [33] = "crnor|crnotCCC=", [129] = "crandcCCC", 31 | [193] = "crxor|crclrCCC%", [225] = "crnandCCC", 32 | [257] = "crandCCC", [289] = "creqv|crsetCCC%", 33 | [417] = "crorcCCC", [449] = "cror|crmoveCCC=", 34 | [16] = "b_lrKB", [528] = "b_ctrKB", 35 | [150] = "isync", 36 | } 37 | 38 | local map_rlwinm = setmetatable({ 39 | shift = 0, mask = -1, 40 | }, 41 | { __index = function(t, x) 42 | local rot = band(rshift(x, 11), 31) 43 | local mb = band(rshift(x, 6), 31) 44 | local me = band(rshift(x, 1), 31) 45 | if mb == 0 and me == 31-rot then 46 | return "slwiRR~A." 47 | elseif me == 31 and mb == 32-rot then 48 | return "srwiRR~-A." 49 | else 50 | return "rlwinmRR~AAA." 51 | end 52 | end 53 | }) 54 | 55 | local map_rld = { 56 | shift = 2, mask = 7, 57 | [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", 58 | { 59 | shift = 1, mask = 1, 60 | [0] = "rldclRR~RM.", "rldcrRR~RM.", 61 | }, 62 | } 63 | 64 | local map_ext = setmetatable({ 65 | shift = 1, mask = 1023, 66 | 67 | [0] = "cmp_YLRR", [32] = "cmpl_YLRR", 68 | [4] = "twARR", [68] = "tdARR", 69 | 70 | [8] = "subfcRRR.", [40] = "subfRRR.", 71 | [104] = "negRR.", [136] = "subfeRRR.", 72 | [200] = "subfzeRR.", [232] = "subfmeRR.", 73 | [520] = "subfcoRRR.", [552] = "subfoRRR.", 74 | [616] = "negoRR.", [648] = "subfeoRRR.", 75 | [712] = "subfzeoRR.", [744] = "subfmeoRR.", 76 | 77 | [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", 78 | [457] = "divduRRR.", [489] = "divdRRR.", 79 | [745] = "mulldoRRR.", 80 | [969] = "divduoRRR.", [1001] = "divdoRRR.", 81 | 82 | [10] = "addcRRR.", [138] = "addeRRR.", 83 | [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", 84 | [522] = "addcoRRR.", [650] = "addeoRRR.", 85 | [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", 86 | 87 | [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", 88 | [459] = "divwuRRR.", [491] = "divwRRR.", 89 | [747] = "mullwoRRR.", 90 | [971] = "divwouRRR.", [1003] = "divwoRRR.", 91 | 92 | [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", 93 | 94 | [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, 95 | [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, 96 | [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, 97 | [339] = { 98 | shift = 11, mask = 1023, 99 | [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", 100 | }, 101 | [467] = { 102 | shift = 11, mask = 1023, 103 | [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", 104 | }, 105 | 106 | [20] = "lwarxRR0R", [84] = "ldarxRR0R", 107 | 108 | [21] = "ldxRR0R", [53] = "lduxRRR", 109 | [149] = "stdxRR0R", [181] = "stduxRRR", 110 | [341] = "lwaxRR0R", [373] = "lwauxRRR", 111 | 112 | [23] = "lwzxRR0R", [55] = "lwzuxRRR", 113 | [87] = "lbzxRR0R", [119] = "lbzuxRRR", 114 | [151] = "stwxRR0R", [183] = "stwuxRRR", 115 | [215] = "stbxRR0R", [247] = "stbuxRRR", 116 | [279] = "lhzxRR0R", [311] = "lhzuxRRR", 117 | [343] = "lhaxRR0R", [375] = "lhauxRRR", 118 | [407] = "sthxRR0R", [439] = "sthuxRRR", 119 | 120 | [54] = "dcbst-R0R", [86] = "dcbf-R0R", 121 | [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", 122 | [246] = "dcbtst-R0R", [278] = "dcbt-R0R", 123 | [310] = "eciwxRR0R", [438] = "ecowxRR0R", 124 | [470] = "dcbi-RR", 125 | 126 | [598] = { 127 | shift = 21, mask = 3, 128 | [0] = "sync", "lwsync", "ptesync", 129 | }, 130 | [758] = "dcba-RR", 131 | [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", 132 | 133 | [26] = "cntlzwRR~", [58] = "cntlzdRR~", 134 | [122] = "popcntbRR~", 135 | [154] = "prtywRR~", [186] = "prtydRR~", 136 | 137 | [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", 138 | [284] = "eqvRR~R.", [316] = "xorRR~R.", 139 | [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", 140 | [508] = "cmpbRR~R", 141 | 142 | [512] = "mcrxrX", 143 | 144 | [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", 145 | 146 | [533] = "lswxRR0R", [597] = "lswiRR0A", 147 | [661] = "stswxRR0R", [725] = "stswiRR0A", 148 | 149 | [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", 150 | [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", 151 | 152 | [535] = "lfsxFR0R", [567] = "lfsuxFRR", 153 | [599] = "lfdxFR0R", [631] = "lfduxFRR", 154 | [663] = "stfsxFR0R", [695] = "stfsuxFRR", 155 | [727] = "stfdxFR0R", [759] = "stfduxFR0R", 156 | [855] = "lfiwaxFR0R", 157 | [983] = "stfiwxFR0R", 158 | 159 | [24] = "slwRR~R.", 160 | 161 | [27] = "sldRR~R.", [536] = "srwRR~R.", 162 | [792] = "srawRR~R.", [824] = "srawiRR~A.", 163 | 164 | [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", 165 | [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", 166 | 167 | [539] = "srdRR~R.", 168 | }, 169 | { __index = function(t, x) 170 | if band(x, 31) == 15 then return "iselRRRC" end 171 | end 172 | }) 173 | 174 | local map_ld = { 175 | shift = 0, mask = 3, 176 | [0] = "ldRRE", "lduRRE", "lwaRRE", 177 | } 178 | 179 | local map_std = { 180 | shift = 0, mask = 3, 181 | [0] = "stdRRE", "stduRRE", 182 | } 183 | 184 | local map_fps = { 185 | shift = 5, mask = 1, 186 | { 187 | shift = 1, mask = 15, 188 | [0] = false, false, "fdivsFFF.", false, 189 | "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, 190 | "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, 191 | "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", 192 | } 193 | } 194 | 195 | local map_fpd = { 196 | shift = 5, mask = 1, 197 | [0] = { 198 | shift = 1, mask = 1023, 199 | [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", 200 | [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", 201 | [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", 202 | [136] = "fnabsF-F.", [264] = "fabsF-F.", 203 | [12] = "frspF-F.", 204 | [14] = "fctiwF-F.", [15] = "fctiwzF-F.", 205 | [583] = "mffsF.", [711] = "mtfsfZF.", 206 | [392] = "frinF-F.", [424] = "frizF-F.", 207 | [456] = "fripF-F.", [488] = "frimF-F.", 208 | [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", 209 | }, 210 | { 211 | shift = 1, mask = 15, 212 | [0] = false, false, "fdivFFF.", false, 213 | "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", 214 | "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, 215 | "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", 216 | } 217 | } 218 | 219 | local map_spe = { 220 | shift = 0, mask = 2047, 221 | 222 | [512] = "evaddwRRR", [514] = "evaddiwRAR~", 223 | [516] = "evsubwRRR~", [518] = "evsubiwRAR~", 224 | [520] = "evabsRR", [521] = "evnegRR", 225 | [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", 226 | [525] = "evcntlzwRR", [526] = "evcntlswRR", 227 | 228 | [527] = "brincRRR", 229 | 230 | [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", 231 | [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", 232 | [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", 233 | 234 | [544] = "evsrwuRRR", [545] = "evsrwsRRR", 235 | [546] = "evsrwiuRRA", [547] = "evsrwisRRA", 236 | [548] = "evslwRRR", [550] = "evslwiRRA", 237 | [552] = "evrlwRRR", [553] = "evsplatiRS", 238 | [554] = "evrlwiRRA", [555] = "evsplatfiRS", 239 | [556] = "evmergehiRRR", [557] = "evmergeloRRR", 240 | [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", 241 | 242 | [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", 243 | [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", 244 | [564] = "evcmpeqYRR", 245 | 246 | [632] = "evselRRR", [633] = "evselRRRW", 247 | [634] = "evselRRRW", [635] = "evselRRRW", 248 | [636] = "evselRRRW", [637] = "evselRRRW", 249 | [638] = "evselRRRW", [639] = "evselRRRW", 250 | 251 | [640] = "evfsaddRRR", [641] = "evfssubRRR", 252 | [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", 253 | [648] = "evfsmulRRR", [649] = "evfsdivRRR", 254 | [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", 255 | [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", 256 | [658] = "evfscfufR-R", [659] = "evfscfsfR-R", 257 | [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", 258 | [662] = "evfsctufR-R", [663] = "evfsctsfR-R", 259 | [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", 260 | [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", 261 | 262 | [704] = "efsaddRRR", [705] = "efssubRRR", 263 | [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", 264 | [712] = "efsmulRRR", [713] = "efsdivRRR", 265 | [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", 266 | [719] = "efscfdR-R", 267 | [720] = "efscfuiR-R", [721] = "efscfsiR-R", 268 | [722] = "efscfufR-R", [723] = "efscfsfR-R", 269 | [724] = "efsctuiR-R", [725] = "efsctsiR-R", 270 | [726] = "efsctufR-R", [727] = "efsctsfR-R", 271 | [728] = "efsctuizR-R", [730] = "efsctsizR-R", 272 | [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", 273 | 274 | [736] = "efdaddRRR", [737] = "efdsubRRR", 275 | [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", 276 | [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", 277 | [744] = "efdmulRRR", [745] = "efddivRRR", 278 | [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", 279 | [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", 280 | [751] = "efdcfsR-R", 281 | [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", 282 | [754] = "efdcfufR-R", [755] = "efdcfsfR-R", 283 | [756] = "efdctuiR-R", [757] = "efdctsiR-R", 284 | [758] = "efdctufR-R", [759] = "efdctsfR-R", 285 | [760] = "efdctuizR-R", [762] = "efdctsizR-R", 286 | [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", 287 | 288 | [768] = "evlddxRR0R", [769] = "evlddRR8", 289 | [770] = "evldwxRR0R", [771] = "evldwRR8", 290 | [772] = "evldhxRR0R", [773] = "evldhRR8", 291 | [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", 292 | [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", 293 | [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", 294 | [784] = "evlwhexRR0R", [785] = "evlwheRR4", 295 | [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", 296 | [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", 297 | [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", 298 | [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", 299 | 300 | [800] = "evstddxRR0R", [801] = "evstddRR8", 301 | [802] = "evstdwxRR0R", [803] = "evstdwRR8", 302 | [804] = "evstdhxRR0R", [805] = "evstdhRR8", 303 | [816] = "evstwhexRR0R", [817] = "evstwheRR4", 304 | [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", 305 | [824] = "evstwwexRR0R", [825] = "evstwweRR4", 306 | [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", 307 | 308 | [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", 309 | [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", 310 | [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", 311 | [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", 312 | [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", 313 | [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", 314 | [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", 315 | [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", 316 | [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", 317 | [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", 318 | [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", 319 | [1147] = "evmwsmfaRRR", 320 | 321 | [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", 322 | [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", 323 | [1220] = "evmraRR", 324 | [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", 325 | [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", 326 | [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", 327 | 328 | [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", 329 | [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", 330 | [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", 331 | [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", 332 | [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", 333 | [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", 334 | [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", 335 | [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", 336 | [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", 337 | [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", 338 | [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", 339 | [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", 340 | [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", 341 | [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", 342 | [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", 343 | [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", 344 | [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", 345 | [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", 346 | [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", 347 | [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", 348 | [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", 349 | [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", 350 | [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", 351 | [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", 352 | [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", 353 | [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", 354 | } 355 | 356 | local map_pri = { 357 | [0] = false, false, "tdiARI", "twiARI", 358 | map_spe, false, false, "mulliRRI", 359 | "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", 360 | "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", 361 | "b_KBJ", "sc", "bKJ", map_crops, 362 | "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", 363 | "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", 364 | "andi.RR~U", "andis.RR~U", map_rld, map_ext, 365 | "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", 366 | "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", 367 | "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", 368 | "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", 369 | "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", 370 | "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", 371 | false, false, map_ld, map_fps, 372 | false, false, map_std, map_fpd, 373 | } 374 | 375 | ------------------------------------------------------------------------------ 376 | 377 | local map_gpr = { 378 | [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", 379 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 380 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 381 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 382 | } 383 | 384 | local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } 385 | 386 | -- Format a condition bit. 387 | local function condfmt(cond) 388 | if cond <= 3 then 389 | return map_cond[band(cond, 3)] 390 | else 391 | return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) 392 | end 393 | end 394 | 395 | ------------------------------------------------------------------------------ 396 | 397 | -- Output a nicely formatted line with an opcode and operands. 398 | local function putop(ctx, text, operands) 399 | local pos = ctx.pos 400 | local extra = "" 401 | if ctx.rel then 402 | local sym = ctx.symtab[ctx.rel] 403 | if sym then extra = "\t->"..sym end 404 | end 405 | if ctx.hexdump > 0 then 406 | ctx.out(format("%08x %s %-7s %s%s\n", 407 | ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) 408 | else 409 | ctx.out(format("%08x %-7s %s%s\n", 410 | ctx.addr+pos, text, concat(operands, ", "), extra)) 411 | end 412 | ctx.pos = pos + 4 413 | end 414 | 415 | -- Fallback for unknown opcodes. 416 | local function unknown(ctx) 417 | return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) 418 | end 419 | 420 | -- Disassemble a single instruction. 421 | local function disass_ins(ctx) 422 | local pos = ctx.pos 423 | local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) 424 | local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) 425 | local operands = {} 426 | local last = nil 427 | local rs = 21 428 | ctx.op = op 429 | ctx.rel = nil 430 | 431 | local opat = map_pri[rshift(b0, 2)] 432 | while type(opat) ~= "string" do 433 | if not opat then return unknown(ctx) end 434 | opat = opat[band(rshift(op, opat.shift), opat.mask)] 435 | end 436 | local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") 437 | local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") 438 | if altname then pat = pat2 end 439 | 440 | for p in gmatch(pat, ".") do 441 | local x = nil 442 | if p == "R" then 443 | x = map_gpr[band(rshift(op, rs), 31)] 444 | rs = rs - 5 445 | elseif p == "F" then 446 | x = "f"..band(rshift(op, rs), 31) 447 | rs = rs - 5 448 | elseif p == "A" then 449 | x = band(rshift(op, rs), 31) 450 | rs = rs - 5 451 | elseif p == "S" then 452 | x = arshift(lshift(op, 27-rs), 27) 453 | rs = rs - 5 454 | elseif p == "I" then 455 | x = arshift(lshift(op, 16), 16) 456 | elseif p == "U" then 457 | x = band(op, 0xffff) 458 | elseif p == "D" or p == "E" then 459 | local disp = arshift(lshift(op, 16), 16) 460 | if p == "E" then disp = band(disp, -4) end 461 | if last == "r0" then last = "0" end 462 | operands[#operands] = format("%d(%s)", disp, last) 463 | elseif p >= "2" and p <= "8" then 464 | local disp = band(rshift(op, rs), 31) * p 465 | if last == "r0" then last = "0" end 466 | operands[#operands] = format("%d(%s)", disp, last) 467 | elseif p == "H" then 468 | x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) 469 | rs = rs - 5 470 | elseif p == "M" then 471 | x = band(rshift(op, rs), 31) + band(op, 0x20) 472 | elseif p == "C" then 473 | x = condfmt(band(rshift(op, rs), 31)) 474 | rs = rs - 5 475 | elseif p == "B" then 476 | local bo = rshift(op, 21) 477 | local cond = band(rshift(op, 16), 31) 478 | local cn = "" 479 | rs = rs - 10 480 | if band(bo, 4) == 0 then 481 | cn = band(bo, 2) == 0 and "dnz" or "dz" 482 | if band(bo, 0x10) == 0 then 483 | cn = cn..(band(bo, 8) == 0 and "f" or "t") 484 | end 485 | if band(bo, 0x10) == 0 then x = condfmt(cond) end 486 | name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") 487 | elseif band(bo, 0x10) == 0 then 488 | cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] 489 | if cond > 3 then x = "cr"..rshift(cond, 2) end 490 | name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") 491 | end 492 | name = gsub(name, "_", cn) 493 | elseif p == "J" then 494 | x = arshift(lshift(op, 27-rs), 29-rs)*4 495 | if band(op, 2) == 0 then x = ctx.addr + pos + x end 496 | ctx.rel = x 497 | x = "0x"..tohex(x) 498 | elseif p == "K" then 499 | if band(op, 1) ~= 0 then name = name.."l" end 500 | if band(op, 2) ~= 0 then name = name.."a" end 501 | elseif p == "X" or p == "Y" then 502 | x = band(rshift(op, rs+2), 7) 503 | if x == 0 and p == "Y" then x = nil else x = "cr"..x end 504 | rs = rs - 5 505 | elseif p == "W" then 506 | x = "cr"..band(op, 7) 507 | elseif p == "Z" then 508 | x = band(rshift(op, rs-4), 255) 509 | rs = rs - 10 510 | elseif p == ">" then 511 | operands[#operands] = rshift(operands[#operands], 1) 512 | elseif p == "0" then 513 | if last == "r0" then 514 | operands[#operands] = nil 515 | if altname then name = altname end 516 | end 517 | elseif p == "L" then 518 | name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") 519 | elseif p == "." then 520 | if band(op, 1) == 1 then name = name.."." end 521 | elseif p == "N" then 522 | if op == 0x60000000 then name = "nop"; break end 523 | elseif p == "~" then 524 | local n = #operands 525 | operands[n-1], operands[n] = operands[n], operands[n-1] 526 | elseif p == "=" then 527 | local n = #operands 528 | if last == operands[n-1] then 529 | operands[n] = nil 530 | name = altname 531 | end 532 | elseif p == "%" then 533 | local n = #operands 534 | if last == operands[n-1] and last == operands[n-2] then 535 | operands[n] = nil 536 | operands[n-1] = nil 537 | name = altname 538 | end 539 | elseif p == "-" then 540 | rs = rs - 5 541 | else 542 | assert(false) 543 | end 544 | if x then operands[#operands+1] = x; last = x end 545 | end 546 | 547 | return putop(ctx, name, operands) 548 | end 549 | 550 | ------------------------------------------------------------------------------ 551 | 552 | -- Disassemble a block of code. 553 | local function disass_block(ctx, ofs, len) 554 | if not ofs then ofs = 0 end 555 | local stop = len and ofs+len or #ctx.code 556 | stop = stop - stop % 4 557 | ctx.pos = ofs - ofs % 4 558 | ctx.rel = nil 559 | while ctx.pos < stop do disass_ins(ctx) end 560 | end 561 | 562 | -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 563 | local function create_(code, addr, out) 564 | local ctx = {} 565 | ctx.code = code 566 | ctx.addr = addr or 0 567 | ctx.out = out or io.write 568 | ctx.symtab = {} 569 | ctx.disass = disass_block 570 | ctx.hexdump = 8 571 | return ctx 572 | end 573 | 574 | -- Simple API: disassemble code (a string) at address and output via out. 575 | local function disass_(code, addr, out) 576 | create_(code, addr, out):disass() 577 | end 578 | 579 | -- Return register name for RID. 580 | local function regname_(r) 581 | if r < 32 then return map_gpr[r] end 582 | return "f"..(r-32) 583 | end 584 | 585 | -- Public module functions. 586 | module(...) 587 | 588 | create = create_ 589 | disass = disass_ 590 | regname = regname_ 591 | 592 | -------------------------------------------------------------------------------- /jit/dis_x64.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT x64 disassembler wrapper module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This module just exports the 64 bit functions from the combined 8 | -- x86/x64 disassembler module. All the interesting stuff is there. 9 | ------------------------------------------------------------------------------ 10 | 11 | local require = require 12 | 13 | module(...) 14 | 15 | local dis_x86 = require(_PACKAGE.."dis_x86") 16 | 17 | create = dis_x86.create64 18 | disass = dis_x86.disass64 19 | regname = dis_x86.regname64 20 | 21 | -------------------------------------------------------------------------------- /jit/dis_x86.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT x86/x64 disassembler module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- This is a helper module used by the LuaJIT machine code dumper module. 8 | -- 9 | -- Sending small code snippets to an external disassembler and mixing the 10 | -- output with our own stuff was too fragile. So I had to bite the bullet 11 | -- and write yet another x86 disassembler. Oh well ... 12 | -- 13 | -- The output format is very similar to what ndisasm generates. But it has 14 | -- been developed independently by looking at the opcode tables from the 15 | -- Intel and AMD manuals. The supported instruction set is quite extensive 16 | -- and reflects what a current generation Intel or AMD CPU implements in 17 | -- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3, 18 | -- SSE4.1, SSE4.2, SSE4a and even privileged and hypervisor (VMX/SVM) 19 | -- instructions. 20 | -- 21 | -- Notes: 22 | -- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported. 23 | -- * No attempt at optimization has been made -- it's fast enough for my needs. 24 | -- * The public API may change when more architectures are added. 25 | ------------------------------------------------------------------------------ 26 | 27 | local type = type 28 | local sub, byte, format = string.sub, string.byte, string.format 29 | local match, gmatch, gsub = string.match, string.gmatch, string.gsub 30 | local lower, rep = string.lower, string.rep 31 | 32 | -- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on. 33 | local map_opc1_32 = { 34 | --0x 35 | [0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es", 36 | "orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*", 37 | --1x 38 | "adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss", 39 | "sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds", 40 | --2x 41 | "andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa", 42 | "subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das", 43 | --3x 44 | "xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa", 45 | "cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas", 46 | --4x 47 | "incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR", 48 | "decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR", 49 | --5x 50 | "pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR", 51 | "popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR", 52 | --6x 53 | "sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr", 54 | "fs:seg","gs:seg","o16:","a16", 55 | "pushUi","imulVrmi","pushBs","imulVrms", 56 | "insb","insVS","outsb","outsVS", 57 | --7x 58 | "joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj", 59 | "jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj", 60 | --8x 61 | "arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms", 62 | "testBmr","testVmr","xchgBrm","xchgVrm", 63 | "movBmr","movVmr","movBrm","movVrm", 64 | "movVmg","leaVrm","movWgm","popUm", 65 | --9x 66 | "nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR", 67 | "xchgVaR","xchgVaR","xchgVaR","xchgVaR", 68 | "sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait", 69 | "sz*pushfw,pushf","sz*popfw,popf","sahf","lahf", 70 | --Ax 71 | "movBao","movVao","movBoa","movVoa", 72 | "movsb","movsVS","cmpsb","cmpsVS", 73 | "testBai","testVai","stosb","stosVS", 74 | "lodsb","lodsVS","scasb","scasVS", 75 | --Bx 76 | "movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi", 77 | "movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI", 78 | --Cx 79 | "shift!Bmu","shift!Vmu","retBw","ret","$lesVrm","$ldsVrm","movBmi","movVmi", 80 | "enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS", 81 | --Dx 82 | "shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb", 83 | "fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7", 84 | --Ex 85 | "loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj", 86 | "inBau","inVau","outBua","outVua", 87 | "callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda", 88 | --Fx 89 | "lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm", 90 | "clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm", 91 | } 92 | assert(#map_opc1_32 == 255) 93 | 94 | -- Map for 1st opcode byte in 64 bit mode (overrides only). 95 | local map_opc1_64 = setmetatable({ 96 | [0x06]=false, [0x07]=false, [0x0e]=false, 97 | [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false, 98 | [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false, 99 | [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:", 100 | [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb", 101 | [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb", 102 | [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb", 103 | [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb", 104 | [0x82]=false, [0x9a]=false, [0xc4]=false, [0xc5]=false, [0xce]=false, 105 | [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false, 106 | }, { __index = map_opc1_32 }) 107 | 108 | -- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you. 109 | -- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2 110 | local map_opc2 = { 111 | --0x 112 | [0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret", 113 | "invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu", 114 | --1x 115 | "movupsXrm|movssXrm|movupdXrm|movsdXrm", 116 | "movupsXmr|movssXmr|movupdXmr|movsdXmr", 117 | "movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", 118 | "movlpsXmr||movlpdXmr", 119 | "unpcklpsXrm||unpcklpdXrm", 120 | "unpckhpsXrm||unpckhpdXrm", 121 | "movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm", 122 | "movhpsXmr||movhpdXmr", 123 | "$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm", 124 | "hintnopVm","hintnopVm","hintnopVm","hintnopVm", 125 | --2x 126 | "movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil, 127 | "movapsXrm||movapdXrm", 128 | "movapsXmr||movapdXmr", 129 | "cvtpi2psXrMm|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt", 130 | "movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr", 131 | "cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm", 132 | "cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm", 133 | "ucomissXrm||ucomisdXrm", 134 | "comissXrm||comisdXrm", 135 | --3x 136 | "wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec", 137 | "opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil, 138 | --4x 139 | "cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm", 140 | "cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm", 141 | "cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm", 142 | "cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm", 143 | --5x 144 | "movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm", 145 | "rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm", 146 | "andpsXrm||andpdXrm","andnpsXrm||andnpdXrm", 147 | "orpsXrm||orpdXrm","xorpsXrm||xorpdXrm", 148 | "addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm", 149 | "cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm", 150 | "cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm", 151 | "subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm", 152 | "divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm", 153 | --6x 154 | "punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm", 155 | "pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm", 156 | "punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm", 157 | "||punpcklqdqXrm","||punpckhqdqXrm", 158 | "movPrVSm","movqMrm|movdquXrm|movdqaXrm", 159 | --7x 160 | "pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu", 161 | "pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu", 162 | "pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|", 163 | "vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$", 164 | nil,nil, 165 | "||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm", 166 | "movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr", 167 | --8x 168 | "joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj", 169 | "jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj", 170 | --9x 171 | "setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm", 172 | "setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm", 173 | --Ax 174 | "push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil, 175 | "push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm", 176 | --Bx 177 | "cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr", 178 | "$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt", 179 | "|popcntVrm","ud2Dp","bt!Vmu","btcVmr", 180 | "bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt", 181 | --Cx 182 | "xaddBmr","xaddVmr", 183 | "cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|", 184 | "pinsrwPrWmu","pextrwDrPmu", 185 | "shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp", 186 | "bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR", 187 | --Dx 188 | "||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm", 189 | "paddqPrm","pmullwPrm", 190 | "|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm", 191 | "psubusbPrm","psubuswPrm","pminubPrm","pandPrm", 192 | "paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm", 193 | --Ex 194 | "pavgbPrm","psrawPrm","psradPrm","pavgwPrm", 195 | "pmulhuwPrm","pmulhwPrm", 196 | "|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr", 197 | "psubsbPrm","psubswPrm","pminswPrm","porPrm", 198 | "paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm", 199 | --Fx 200 | "|||lddquXrm","psllwPrm","pslldPrm","psllqPrm", 201 | "pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$", 202 | "psubbPrm","psubwPrm","psubdPrm","psubqPrm", 203 | "paddbPrm","paddwPrm","padddPrm","ud", 204 | } 205 | assert(map_opc2[255] == "ud") 206 | 207 | -- Map for three-byte opcodes. Can't wait for their next invention. 208 | local map_opc3 = { 209 | ["38"] = { -- [66] 0f 38 xx 210 | --0x 211 | [0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm", 212 | "pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm", 213 | "psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm", 214 | nil,nil,nil,nil, 215 | --1x 216 | "||pblendvbXrma",nil,nil,nil, 217 | "||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm", 218 | nil,nil,nil,nil, 219 | "pabsbPrm","pabswPrm","pabsdPrm",nil, 220 | --2x 221 | "||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm", 222 | "||pmovsxwqXrm","||pmovsxdqXrm",nil,nil, 223 | "||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm", 224 | nil,nil,nil,nil, 225 | --3x 226 | "||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm", 227 | "||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm", 228 | "||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm", 229 | "||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm", 230 | --4x 231 | "||pmulddXrm","||phminposuwXrm", 232 | --Fx 233 | [0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt", 234 | }, 235 | 236 | ["3a"] = { -- [66] 0f 3a xx 237 | --0x 238 | [0x00]=nil,nil,nil,nil,nil,nil,nil,nil, 239 | "||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu", 240 | "||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu", 241 | --1x 242 | nil,nil,nil,nil, 243 | "||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", 244 | nil,nil,nil,nil,nil,nil,nil,nil, 245 | --2x 246 | "||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil, 247 | --4x 248 | [0x40] = "||dppsXrmu", 249 | [0x41] = "||dppdXrmu", 250 | [0x42] = "||mpsadbwXrmu", 251 | --6x 252 | [0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu", 253 | [0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu", 254 | }, 255 | } 256 | 257 | -- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands). 258 | local map_opcvm = { 259 | [0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff", 260 | [0xc8]="monitor",[0xc9]="mwait", 261 | [0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave", 262 | [0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga", 263 | [0xf8]="swapgs",[0xf9]="rdtscp", 264 | } 265 | 266 | -- Map for FP opcodes. And you thought stack machines are simple? 267 | local map_opcfp = { 268 | -- D8-DF 00-BF: opcodes with a memory operand. 269 | -- D8 270 | [0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm", 271 | "fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm", 272 | -- DA 273 | "fiaddDm","fimulDm","ficomDm","ficompDm", 274 | "fisubDm","fisubrDm","fidivDm","fidivrDm", 275 | -- DB 276 | "fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp", 277 | -- DC 278 | "faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm", 279 | -- DD 280 | "fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm", 281 | -- DE 282 | "fiaddWm","fimulWm","ficomWm","ficompWm", 283 | "fisubWm","fisubrWm","fidivWm","fidivrWm", 284 | -- DF 285 | "fildWm","fisttpWm","fistWm","fistpWm", 286 | "fbld twordFmp","fildQm","fbstp twordFmp","fistpQm", 287 | -- xx C0-FF: opcodes with a pseudo-register operand. 288 | -- D8 289 | "faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf", 290 | -- D9 291 | "fldFf","fxchFf",{"fnop"},nil, 292 | {"fchs","fabs",nil,nil,"ftst","fxam"}, 293 | {"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"}, 294 | {"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"}, 295 | {"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"}, 296 | -- DA 297 | "fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil, 298 | -- DB 299 | "fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf", 300 | {nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil, 301 | -- DC 302 | "fadd toFf","fmul toFf",nil,nil, 303 | "fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf", 304 | -- DD 305 | "ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil, 306 | -- DE 307 | "faddpFf","fmulpFf",nil,{nil,"fcompp"}, 308 | "fsubrpFf","fsubpFf","fdivrpFf","fdivpFf", 309 | -- DF 310 | nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil, 311 | } 312 | assert(map_opcfp[126] == "fcomipFf") 313 | 314 | -- Map for opcode groups. The subkey is sp from the ModRM byte. 315 | local map_opcgroup = { 316 | arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, 317 | shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" }, 318 | testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" }, 319 | testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" }, 320 | incb = { "inc", "dec" }, 321 | incd = { "inc", "dec", "callUmp", "$call farDmp", 322 | "jmpUmp", "$jmp farDmp", "pushUm" }, 323 | sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" }, 324 | sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt", 325 | "smsw", nil, "lmsw", "vm*$invlpg" }, 326 | bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" }, 327 | cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil, 328 | nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" }, 329 | pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" }, 330 | pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" }, 331 | pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" }, 332 | pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" }, 333 | fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr", 334 | nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" }, 335 | prefetch = { "prefetch", "prefetchw" }, 336 | prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" }, 337 | } 338 | 339 | ------------------------------------------------------------------------------ 340 | 341 | -- Maps for register names. 342 | local map_regs = { 343 | B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", 344 | "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, 345 | B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", 346 | "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, 347 | W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", 348 | "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }, 349 | D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", 350 | "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }, 351 | Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", 352 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }, 353 | M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", 354 | "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext! 355 | X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", 356 | "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" }, 357 | } 358 | local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } 359 | 360 | -- Maps for size names. 361 | local map_sz2n = { 362 | B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, 363 | } 364 | local map_sz2prefix = { 365 | B = "byte", W = "word", D = "dword", 366 | Q = "qword", 367 | M = "qword", X = "xword", 368 | F = "dword", G = "qword", -- No need for sizes/register names for these two. 369 | } 370 | 371 | ------------------------------------------------------------------------------ 372 | 373 | -- Output a nicely formatted line with an opcode and operands. 374 | local function putop(ctx, text, operands) 375 | local code, pos, hex = ctx.code, ctx.pos, "" 376 | local hmax = ctx.hexdump 377 | if hmax > 0 then 378 | for i=ctx.start,pos-1 do 379 | hex = hex..format("%02X", byte(code, i, i)) 380 | end 381 | if #hex > hmax then hex = sub(hex, 1, hmax)..". " 382 | else hex = hex..rep(" ", hmax-#hex+2) end 383 | end 384 | if operands then text = text.." "..operands end 385 | if ctx.o16 then text = "o16 "..text; ctx.o16 = false end 386 | if ctx.a32 then text = "a32 "..text; ctx.a32 = false end 387 | if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end 388 | if ctx.rex then 389 | local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "").. 390 | (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "") 391 | if t ~= "" then text = "rex."..t.." "..text end 392 | ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false 393 | ctx.rex = false 394 | end 395 | if ctx.seg then 396 | local text2, n = gsub(text, "%[", "["..ctx.seg..":") 397 | if n == 0 then text = ctx.seg.." "..text else text = text2 end 398 | ctx.seg = false 399 | end 400 | if ctx.lock then text = "lock "..text; ctx.lock = false end 401 | local imm = ctx.imm 402 | if imm then 403 | local sym = ctx.symtab[imm] 404 | if sym then text = text.."\t->"..sym end 405 | end 406 | ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text)) 407 | ctx.mrm = false 408 | ctx.start = pos 409 | ctx.imm = nil 410 | end 411 | 412 | -- Clear all prefix flags. 413 | local function clearprefixes(ctx) 414 | ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false 415 | ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false 416 | ctx.rex = false; ctx.a32 = false 417 | end 418 | 419 | -- Fallback for incomplete opcodes at the end. 420 | local function incomplete(ctx) 421 | ctx.pos = ctx.stop+1 422 | clearprefixes(ctx) 423 | return putop(ctx, "(incomplete)") 424 | end 425 | 426 | -- Fallback for unknown opcodes. 427 | local function unknown(ctx) 428 | clearprefixes(ctx) 429 | return putop(ctx, "(unknown)") 430 | end 431 | 432 | -- Return an immediate of the specified size. 433 | local function getimm(ctx, pos, n) 434 | if pos+n-1 > ctx.stop then return incomplete(ctx) end 435 | local code = ctx.code 436 | if n == 1 then 437 | local b1 = byte(code, pos, pos) 438 | return b1 439 | elseif n == 2 then 440 | local b1, b2 = byte(code, pos, pos+1) 441 | return b1+b2*256 442 | else 443 | local b1, b2, b3, b4 = byte(code, pos, pos+3) 444 | local imm = b1+b2*256+b3*65536+b4*16777216 445 | ctx.imm = imm 446 | return imm 447 | end 448 | end 449 | 450 | -- Process pattern string and generate the operands. 451 | local function putpat(ctx, name, pat) 452 | local operands, regs, sz, mode, sp, rm, sc, rx, sdisp 453 | local code, pos, stop = ctx.code, ctx.pos, ctx.stop 454 | 455 | -- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz 456 | for p in gmatch(pat, ".") do 457 | local x = nil 458 | if p == "V" or p == "U" then 459 | if ctx.rexw then sz = "Q"; ctx.rexw = false 460 | elseif ctx.o16 then sz = "W"; ctx.o16 = false 461 | elseif p == "U" and ctx.x64 then sz = "Q" 462 | else sz = "D" end 463 | regs = map_regs[sz] 464 | elseif p == "T" then 465 | if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end 466 | regs = map_regs[sz] 467 | elseif p == "B" then 468 | sz = "B" 469 | regs = ctx.rex and map_regs.B64 or map_regs.B 470 | elseif match(p, "[WDQMXFG]") then 471 | sz = p 472 | regs = map_regs[sz] 473 | elseif p == "P" then 474 | sz = ctx.o16 and "X" or "M"; ctx.o16 = false 475 | regs = map_regs[sz] 476 | elseif p == "S" then 477 | name = name..lower(sz) 478 | elseif p == "s" then 479 | local imm = getimm(ctx, pos, 1); if not imm then return end 480 | x = imm <= 127 and format("+0x%02x", imm) 481 | or format("-0x%02x", 256-imm) 482 | pos = pos+1 483 | elseif p == "u" then 484 | local imm = getimm(ctx, pos, 1); if not imm then return end 485 | x = format("0x%02x", imm) 486 | pos = pos+1 487 | elseif p == "w" then 488 | local imm = getimm(ctx, pos, 2); if not imm then return end 489 | x = format("0x%x", imm) 490 | pos = pos+2 491 | elseif p == "o" then -- [offset] 492 | if ctx.x64 then 493 | local imm1 = getimm(ctx, pos, 4); if not imm1 then return end 494 | local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end 495 | x = format("[0x%08x%08x]", imm2, imm1) 496 | pos = pos+8 497 | else 498 | local imm = getimm(ctx, pos, 4); if not imm then return end 499 | x = format("[0x%08x]", imm) 500 | pos = pos+4 501 | end 502 | elseif p == "i" or p == "I" then 503 | local n = map_sz2n[sz] 504 | if n == 8 and ctx.x64 and p == "I" then 505 | local imm1 = getimm(ctx, pos, 4); if not imm1 then return end 506 | local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end 507 | x = format("0x%08x%08x", imm2, imm1) 508 | else 509 | if n == 8 then n = 4 end 510 | local imm = getimm(ctx, pos, n); if not imm then return end 511 | if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then 512 | imm = (0xffffffff+1)-imm 513 | x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm) 514 | else 515 | x = format(imm > 65535 and "0x%08x" or "0x%x", imm) 516 | end 517 | end 518 | pos = pos+n 519 | elseif p == "j" then 520 | local n = map_sz2n[sz] 521 | if n == 8 then n = 4 end 522 | local imm = getimm(ctx, pos, n); if not imm then return end 523 | if sz == "B" and imm > 127 then imm = imm-256 524 | elseif imm > 2147483647 then imm = imm-4294967296 end 525 | pos = pos+n 526 | imm = imm + pos + ctx.addr 527 | if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end 528 | ctx.imm = imm 529 | if sz == "W" then 530 | x = format("word 0x%04x", imm%65536) 531 | elseif ctx.x64 then 532 | local lo = imm % 0x1000000 533 | x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo) 534 | else 535 | x = format("0x%08x", imm) 536 | end 537 | elseif p == "R" then 538 | local r = byte(code, pos-1, pos-1)%8 539 | if ctx.rexb then r = r + 8; ctx.rexb = false end 540 | x = regs[r+1] 541 | elseif p == "a" then x = regs[1] 542 | elseif p == "c" then x = "cl" 543 | elseif p == "d" then x = "dx" 544 | elseif p == "1" then x = "1" 545 | else 546 | if not mode then 547 | mode = ctx.mrm 548 | if not mode then 549 | if pos > stop then return incomplete(ctx) end 550 | mode = byte(code, pos, pos) 551 | pos = pos+1 552 | end 553 | rm = mode%8; mode = (mode-rm)/8 554 | sp = mode%8; mode = (mode-sp)/8 555 | sdisp = "" 556 | if mode < 3 then 557 | if rm == 4 then 558 | if pos > stop then return incomplete(ctx) end 559 | sc = byte(code, pos, pos) 560 | pos = pos+1 561 | rm = sc%8; sc = (sc-rm)/8 562 | rx = sc%8; sc = (sc-rx)/8 563 | if ctx.rexx then rx = rx + 8; ctx.rexx = false end 564 | if rx == 4 then rx = nil end 565 | end 566 | if mode > 0 or rm == 5 then 567 | local dsz = mode 568 | if dsz ~= 1 then dsz = 4 end 569 | local disp = getimm(ctx, pos, dsz); if not disp then return end 570 | if mode == 0 then rm = nil end 571 | if rm or rx or (not sc and ctx.x64 and not ctx.a32) then 572 | if dsz == 1 and disp > 127 then 573 | sdisp = format("-0x%x", 256-disp) 574 | elseif disp >= 0 and disp <= 0x7fffffff then 575 | sdisp = format("+0x%x", disp) 576 | else 577 | sdisp = format("-0x%x", (0xffffffff+1)-disp) 578 | end 579 | else 580 | sdisp = format(ctx.x64 and not ctx.a32 and 581 | not (disp >= 0 and disp <= 0x7fffffff) 582 | and "0xffffffff%08x" or "0x%08x", disp) 583 | end 584 | pos = pos+dsz 585 | end 586 | end 587 | if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end 588 | if ctx.rexr then sp = sp + 8; ctx.rexr = false end 589 | end 590 | if p == "m" then 591 | if mode == 3 then x = regs[rm+1] 592 | else 593 | local aregs = ctx.a32 and map_regs.D or ctx.aregs 594 | local srm, srx = "", "" 595 | if rm then srm = aregs[rm+1] 596 | elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end 597 | ctx.a32 = false 598 | if rx then 599 | if rm then srm = srm.."+" end 600 | srx = aregs[rx+1] 601 | if sc > 0 then srx = srx.."*"..(2^sc) end 602 | end 603 | x = format("[%s%s%s]", srm, srx, sdisp) 604 | end 605 | if mode < 3 and 606 | (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck. 607 | x = map_sz2prefix[sz].." "..x 608 | end 609 | elseif p == "r" then x = regs[sp+1] 610 | elseif p == "g" then x = map_segregs[sp+1] 611 | elseif p == "p" then -- Suppress prefix. 612 | elseif p == "f" then x = "st"..rm 613 | elseif p == "x" then 614 | if sp == 0 and ctx.lock and not ctx.x64 then 615 | x = "CR8"; ctx.lock = false 616 | else 617 | x = "CR"..sp 618 | end 619 | elseif p == "y" then x = "DR"..sp 620 | elseif p == "z" then x = "TR"..sp 621 | elseif p == "t" then 622 | else 623 | error("bad pattern `"..pat.."'") 624 | end 625 | end 626 | if x then operands = operands and operands..", "..x or x end 627 | end 628 | ctx.pos = pos 629 | return putop(ctx, name, operands) 630 | end 631 | 632 | -- Forward declaration. 633 | local map_act 634 | 635 | -- Fetch and cache MRM byte. 636 | local function getmrm(ctx) 637 | local mrm = ctx.mrm 638 | if not mrm then 639 | local pos = ctx.pos 640 | if pos > ctx.stop then return nil end 641 | mrm = byte(ctx.code, pos, pos) 642 | ctx.pos = pos+1 643 | ctx.mrm = mrm 644 | end 645 | return mrm 646 | end 647 | 648 | -- Dispatch to handler depending on pattern. 649 | local function dispatch(ctx, opat, patgrp) 650 | if not opat then return unknown(ctx) end 651 | if match(opat, "%|") then -- MMX/SSE variants depending on prefix. 652 | local p 653 | if ctx.rep then 654 | p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)" 655 | ctx.rep = false 656 | elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false 657 | else p = "^[^%|]*" end 658 | opat = match(opat, p) 659 | if not opat then return unknown(ctx) end 660 | -- ctx.rep = false; ctx.o16 = false 661 | --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi] 662 | --XXX remove in branches? 663 | end 664 | if match(opat, "%$") then -- reg$mem variants. 665 | local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end 666 | opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)") 667 | if opat == "" then return unknown(ctx) end 668 | end 669 | if opat == "" then return unknown(ctx) end 670 | local name, pat = match(opat, "^([a-z0-9 ]*)(.*)") 671 | if pat == "" and patgrp then pat = patgrp end 672 | return map_act[sub(pat, 1, 1)](ctx, name, pat) 673 | end 674 | 675 | -- Get a pattern from an opcode map and dispatch to handler. 676 | local function dispatchmap(ctx, opcmap) 677 | local pos = ctx.pos 678 | local opat = opcmap[byte(ctx.code, pos, pos)] 679 | pos = pos + 1 680 | ctx.pos = pos 681 | return dispatch(ctx, opat) 682 | end 683 | 684 | -- Map for action codes. The key is the first char after the name. 685 | map_act = { 686 | -- Simple opcodes without operands. 687 | [""] = function(ctx, name, pat) 688 | return putop(ctx, name) 689 | end, 690 | 691 | -- Operand size chars fall right through. 692 | B = putpat, W = putpat, D = putpat, Q = putpat, 693 | V = putpat, U = putpat, T = putpat, 694 | M = putpat, X = putpat, P = putpat, 695 | F = putpat, G = putpat, 696 | 697 | -- Collect prefixes. 698 | [":"] = function(ctx, name, pat) 699 | ctx[pat == ":" and name or sub(pat, 2)] = name 700 | if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes. 701 | end, 702 | 703 | -- Chain to special handler specified by name. 704 | ["*"] = function(ctx, name, pat) 705 | return map_act[name](ctx, name, sub(pat, 2)) 706 | end, 707 | 708 | -- Use named subtable for opcode group. 709 | ["!"] = function(ctx, name, pat) 710 | local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end 711 | return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2)) 712 | end, 713 | 714 | -- o16,o32[,o64] variants. 715 | sz = function(ctx, name, pat) 716 | if ctx.o16 then ctx.o16 = false 717 | else 718 | pat = match(pat, ",(.*)") 719 | if ctx.rexw then 720 | local p = match(pat, ",(.*)") 721 | if p then pat = p; ctx.rexw = false end 722 | end 723 | end 724 | pat = match(pat, "^[^,]*") 725 | return dispatch(ctx, pat) 726 | end, 727 | 728 | -- Two-byte opcode dispatch. 729 | opc2 = function(ctx, name, pat) 730 | return dispatchmap(ctx, map_opc2) 731 | end, 732 | 733 | -- Three-byte opcode dispatch. 734 | opc3 = function(ctx, name, pat) 735 | return dispatchmap(ctx, map_opc3[pat]) 736 | end, 737 | 738 | -- VMX/SVM dispatch. 739 | vm = function(ctx, name, pat) 740 | return dispatch(ctx, map_opcvm[ctx.mrm]) 741 | end, 742 | 743 | -- Floating point opcode dispatch. 744 | fp = function(ctx, name, pat) 745 | local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end 746 | local rm = mrm%8 747 | local idx = pat*8 + ((mrm-rm)/8)%8 748 | if mrm >= 192 then idx = idx + 64 end 749 | local opat = map_opcfp[idx] 750 | if type(opat) == "table" then opat = opat[rm+1] end 751 | return dispatch(ctx, opat) 752 | end, 753 | 754 | -- REX prefix. 755 | rex = function(ctx, name, pat) 756 | if ctx.rex then return unknown(ctx) end -- Only 1 REX prefix allowed. 757 | for p in gmatch(pat, ".") do ctx["rex"..p] = true end 758 | ctx.rex = true 759 | end, 760 | 761 | -- Special case for nop with REX prefix. 762 | nop = function(ctx, name, pat) 763 | return dispatch(ctx, ctx.rex and pat or "nop") 764 | end, 765 | } 766 | 767 | ------------------------------------------------------------------------------ 768 | 769 | -- Disassemble a block of code. 770 | local function disass_block(ctx, ofs, len) 771 | if not ofs then ofs = 0 end 772 | local stop = len and ofs+len or #ctx.code 773 | ofs = ofs + 1 774 | ctx.start = ofs 775 | ctx.pos = ofs 776 | ctx.stop = stop 777 | ctx.imm = nil 778 | ctx.mrm = false 779 | clearprefixes(ctx) 780 | while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end 781 | if ctx.pos ~= ctx.start then incomplete(ctx) end 782 | end 783 | 784 | -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). 785 | local function create_(code, addr, out) 786 | local ctx = {} 787 | ctx.code = code 788 | ctx.addr = (addr or 0) - 1 789 | ctx.out = out or io.write 790 | ctx.symtab = {} 791 | ctx.disass = disass_block 792 | ctx.hexdump = 16 793 | ctx.x64 = false 794 | ctx.map1 = map_opc1_32 795 | ctx.aregs = map_regs.D 796 | return ctx 797 | end 798 | 799 | local function create64_(code, addr, out) 800 | local ctx = create_(code, addr, out) 801 | ctx.x64 = true 802 | ctx.map1 = map_opc1_64 803 | ctx.aregs = map_regs.Q 804 | return ctx 805 | end 806 | 807 | -- Simple API: disassemble code (a string) at address and output via out. 808 | local function disass_(code, addr, out) 809 | create_(code, addr, out):disass() 810 | end 811 | 812 | local function disass64_(code, addr, out) 813 | create64_(code, addr, out):disass() 814 | end 815 | 816 | -- Return register name for RID. 817 | local function regname_(r) 818 | if r < 8 then return map_regs.D[r+1] end 819 | return map_regs.X[r-7] 820 | end 821 | 822 | local function regname64_(r) 823 | if r < 16 then return map_regs.Q[r+1] end 824 | return map_regs.X[r-15] 825 | end 826 | 827 | -- Public module functions. 828 | module(...) 829 | 830 | create = create_ 831 | create64 = create64_ 832 | disass = disass_ 833 | disass64 = disass64_ 834 | regname = regname_ 835 | regname64 = regname64_ 836 | 837 | -------------------------------------------------------------------------------- /jit/dump.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- LuaJIT compiler dump module. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module can be used to debug the JIT compiler itself. It dumps the 9 | -- code representations and structures used in various compiler stages. 10 | -- 11 | -- Example usage: 12 | -- 13 | -- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)" 14 | -- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R 15 | -- luajit -jdump=is myapp.lua | less -R 16 | -- luajit -jdump=-b myapp.lua 17 | -- luajit -jdump=+aH,myapp.html myapp.lua 18 | -- luajit -jdump=ixT,myapp.dump myapp.lua 19 | -- 20 | -- The first argument specifies the dump mode. The second argument gives 21 | -- the output file name. Default output is to stdout, unless the environment 22 | -- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the 23 | -- module is started. 24 | -- 25 | -- Different features can be turned on or off with the dump mode. If the 26 | -- mode starts with a '+', the following features are added to the default 27 | -- set of features; a '-' removes them. Otherwise the features are replaced. 28 | -- 29 | -- The following dump features are available (* marks the default): 30 | -- 31 | -- * t Print a line for each started, ended or aborted trace (see also -jv). 32 | -- * b Dump the traced bytecode. 33 | -- * i Dump the IR (intermediate representation). 34 | -- r Augment the IR with register/stack slots. 35 | -- s Dump the snapshot map. 36 | -- * m Dump the generated machine code. 37 | -- x Print each taken trace exit. 38 | -- X Print each taken trace exit and the contents of all registers. 39 | -- a Print the IR of aborted traces, too. 40 | -- 41 | -- The output format can be set with the following characters: 42 | -- 43 | -- T Plain text output. 44 | -- A ANSI-colored text output 45 | -- H Colorized HTML + CSS output. 46 | -- 47 | -- The default output format is plain text. It's set to ANSI-colored text 48 | -- if the COLORTERM variable is set. Note: this is independent of any output 49 | -- redirection, which is actually considered a feature. 50 | -- 51 | -- You probably want to use less -R to enjoy viewing ANSI-colored text from 52 | -- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R" 53 | -- 54 | ------------------------------------------------------------------------------ 55 | 56 | -- Cache some library functions and objects. 57 | local jit = require("jit") 58 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 59 | local jutil = require("jit.util") 60 | local vmdef = require("jit.vmdef") 61 | local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc 62 | local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek 63 | local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap 64 | local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr 65 | local bit = require("bit") 66 | local band, shl, shr = bit.band, bit.lshift, bit.rshift 67 | local sub, gsub, format = string.sub, string.gsub, string.format 68 | local byte, char, rep = string.byte, string.char, string.rep 69 | local type, tostring = type, tostring 70 | local stdout, stderr = io.stdout, io.stderr 71 | 72 | -- Load other modules on-demand. 73 | local bcline, disass 74 | 75 | -- Active flag, output file handle and dump mode. 76 | local active, out, dumpmode 77 | 78 | ------------------------------------------------------------------------------ 79 | 80 | local symtabmt = { __index = false } 81 | local symtab = {} 82 | local nexitsym = 0 83 | 84 | -- Fill nested symbol table with per-trace exit stub addresses. 85 | local function fillsymtab_tr(tr, nexit) 86 | local t = {} 87 | symtabmt.__index = t 88 | if jit.arch == "mips" or jit.arch == "mipsel" then 89 | t[traceexitstub(tr, 0)] = "exit" 90 | return 91 | end 92 | for i=0,nexit-1 do 93 | local addr = traceexitstub(tr, i) 94 | t[addr] = tostring(i) 95 | end 96 | local addr = traceexitstub(tr, nexit) 97 | if addr then t[addr] = "stack_check" end 98 | end 99 | 100 | -- Fill symbol table with trace exit stub addresses. 101 | local function fillsymtab(tr, nexit) 102 | local t = symtab 103 | if nexitsym == 0 then 104 | local ircall = vmdef.ircall 105 | for i=0,#ircall do 106 | local addr = ircalladdr(i) 107 | if addr ~= 0 then t[addr] = ircall[i] end 108 | end 109 | end 110 | if nexitsym == 1000000 then -- Per-trace exit stubs. 111 | fillsymtab_tr(tr, nexit) 112 | elseif nexit > nexitsym then -- Shared exit stubs. 113 | for i=nexitsym,nexit-1 do 114 | local addr = traceexitstub(i) 115 | if addr == nil then -- Fall back to per-trace exit stubs. 116 | fillsymtab_tr(tr, nexit) 117 | setmetatable(symtab, symtabmt) 118 | nexit = 1000000 119 | break 120 | end 121 | t[addr] = tostring(i) 122 | end 123 | nexitsym = nexit 124 | end 125 | return t 126 | end 127 | 128 | local function dumpwrite(s) 129 | out:write(s) 130 | end 131 | 132 | -- Disassemble machine code. 133 | local function dump_mcode(tr) 134 | local info = traceinfo(tr) 135 | if not info then return end 136 | local mcode, addr, loop = tracemc(tr) 137 | if not mcode then return end 138 | if not disass then disass = require("jit.dis_"..jit.arch) end 139 | out:write("---- TRACE ", tr, " mcode ", #mcode, "\n") 140 | local ctx = disass.create(mcode, addr, dumpwrite) 141 | ctx.hexdump = 0 142 | ctx.symtab = fillsymtab(tr, info.nexit) 143 | if loop ~= 0 then 144 | symtab[addr+loop] = "LOOP" 145 | ctx:disass(0, loop) 146 | out:write("->LOOP:\n") 147 | ctx:disass(loop, #mcode-loop) 148 | symtab[addr+loop] = nil 149 | else 150 | ctx:disass(0, #mcode) 151 | end 152 | end 153 | 154 | ------------------------------------------------------------------------------ 155 | 156 | local irtype_text = { 157 | [0] = "nil", 158 | "fal", 159 | "tru", 160 | "lud", 161 | "str", 162 | "p32", 163 | "thr", 164 | "pro", 165 | "fun", 166 | "p64", 167 | "cdt", 168 | "tab", 169 | "udt", 170 | "flt", 171 | "num", 172 | "i8 ", 173 | "u8 ", 174 | "i16", 175 | "u16", 176 | "int", 177 | "u32", 178 | "i64", 179 | "u64", 180 | "sfp", 181 | } 182 | 183 | local colortype_ansi = { 184 | [0] = "%s", 185 | "%s", 186 | "%s", 187 | "\027[36m%s\027[m", 188 | "\027[32m%s\027[m", 189 | "%s", 190 | "\027[1m%s\027[m", 191 | "%s", 192 | "\027[1m%s\027[m", 193 | "%s", 194 | "\027[33m%s\027[m", 195 | "\027[31m%s\027[m", 196 | "\027[36m%s\027[m", 197 | "\027[34m%s\027[m", 198 | "\027[34m%s\027[m", 199 | "\027[35m%s\027[m", 200 | "\027[35m%s\027[m", 201 | "\027[35m%s\027[m", 202 | "\027[35m%s\027[m", 203 | "\027[35m%s\027[m", 204 | "\027[35m%s\027[m", 205 | "\027[35m%s\027[m", 206 | "\027[35m%s\027[m", 207 | "\027[35m%s\027[m", 208 | } 209 | 210 | local function colorize_text(s, t) 211 | return s 212 | end 213 | 214 | local function colorize_ansi(s, t) 215 | return format(colortype_ansi[t], s) 216 | end 217 | 218 | local irtype_ansi = setmetatable({}, 219 | { __index = function(tab, t) 220 | local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end }) 221 | 222 | local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", } 223 | 224 | local function colorize_html(s, t) 225 | s = gsub(s, "[<>&]", html_escape) 226 | return format('%s', irtype_text[t], s) 227 | end 228 | 229 | local irtype_html = setmetatable({}, 230 | { __index = function(tab, t) 231 | local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end }) 232 | 233 | local header_html = [[ 234 | 252 | ]] 253 | 254 | local colorize, irtype 255 | 256 | -- Lookup tables to convert some literals into names. 257 | local litname = { 258 | ["SLOAD "] = setmetatable({}, { __index = function(t, mode) 259 | local s = "" 260 | if band(mode, 1) ~= 0 then s = s.."P" end 261 | if band(mode, 2) ~= 0 then s = s.."F" end 262 | if band(mode, 4) ~= 0 then s = s.."T" end 263 | if band(mode, 8) ~= 0 then s = s.."C" end 264 | if band(mode, 16) ~= 0 then s = s.."R" end 265 | if band(mode, 32) ~= 0 then s = s.."I" end 266 | t[mode] = s 267 | return s 268 | end}), 269 | ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", }, 270 | ["CONV "] = setmetatable({}, { __index = function(t, mode) 271 | local s = irtype[band(mode, 31)] 272 | s = irtype[band(shr(mode, 5), 31)].."."..s 273 | if band(mode, 0x400) ~= 0 then s = s.." trunc" 274 | elseif band(mode, 0x800) ~= 0 then s = s.." sext" end 275 | local c = shr(mode, 14) 276 | if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end 277 | t[mode] = s 278 | return s 279 | end}), 280 | ["FLOAD "] = vmdef.irfield, 281 | ["FREF "] = vmdef.irfield, 282 | ["FPMATH"] = vmdef.irfpm, 283 | } 284 | 285 | local function ctlsub(c) 286 | if c == "\n" then return "\\n" 287 | elseif c == "\r" then return "\\r" 288 | elseif c == "\t" then return "\\t" 289 | else return format("\\%03d", byte(c)) 290 | end 291 | end 292 | 293 | local function fmtfunc(func, pc) 294 | local fi = funcinfo(func, pc) 295 | if fi.loc then 296 | return fi.loc 297 | elseif fi.ffid then 298 | return vmdef.ffnames[fi.ffid] 299 | elseif fi.addr then 300 | return format("C:%x", fi.addr) 301 | else 302 | return "(?)" 303 | end 304 | end 305 | 306 | local function formatk(tr, idx) 307 | local k, t, slot = tracek(tr, idx) 308 | local tn = type(k) 309 | local s 310 | if tn == "number" then 311 | if k == 2^52+2^51 then 312 | s = "bias" 313 | else 314 | s = format("%+.14g", k) 315 | end 316 | elseif tn == "string" then 317 | s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub)) 318 | elseif tn == "function" then 319 | s = fmtfunc(k) 320 | elseif tn == "table" then 321 | s = format("{%p}", k) 322 | elseif tn == "userdata" then 323 | if t == 12 then 324 | s = format("userdata:%p", k) 325 | else 326 | s = format("[%p]", k) 327 | if s == "[0x00000000]" then s = "NULL" end 328 | end 329 | elseif t == 21 then -- int64_t 330 | s = sub(tostring(k), 1, -3) 331 | if sub(s, 1, 1) ~= "-" then s = "+"..s end 332 | else 333 | s = tostring(k) -- For primitives. 334 | end 335 | s = colorize(format("%-4s", s), t) 336 | if slot then 337 | s = format("%s @%d", s, slot) 338 | end 339 | return s 340 | end 341 | 342 | local function printsnap(tr, snap) 343 | local n = 2 344 | for s=0,snap[1]-1 do 345 | local sn = snap[n] 346 | if shr(sn, 24) == s then 347 | n = n + 1 348 | local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS 349 | if ref < 0 then 350 | out:write(formatk(tr, ref)) 351 | elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM 352 | out:write(colorize(format("%04d/%04d", ref, ref+1), 14)) 353 | else 354 | local m, ot, op1, op2 = traceir(tr, ref) 355 | out:write(colorize(format("%04d", ref), band(ot, 31))) 356 | end 357 | out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME 358 | else 359 | out:write("---- ") 360 | end 361 | end 362 | out:write("]\n") 363 | end 364 | 365 | -- Dump snapshots (not interleaved with IR). 366 | local function dump_snap(tr) 367 | out:write("---- TRACE ", tr, " snapshots\n") 368 | for i=0,1000000000 do 369 | local snap = tracesnap(tr, i) 370 | if not snap then break end 371 | out:write(format("#%-3d %04d [ ", i, snap[0])) 372 | printsnap(tr, snap) 373 | end 374 | end 375 | 376 | -- Return a register name or stack slot for a rid/sp location. 377 | local function ridsp_name(ridsp, ins) 378 | if not disass then disass = require("jit.dis_"..jit.arch) end 379 | local rid, slot = band(ridsp, 0xff), shr(ridsp, 8) 380 | if rid == 253 or rid == 254 then 381 | return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot) 382 | end 383 | if ridsp > 255 then return format("[%x]", slot*4) end 384 | if rid < 128 then return disass.regname(rid) end 385 | return "" 386 | end 387 | 388 | -- Dump CALL* function ref and return optional ctype. 389 | local function dumpcallfunc(tr, ins) 390 | local ctype 391 | if ins > 0 then 392 | local m, ot, op1, op2 = traceir(tr, ins) 393 | if band(ot, 31) == 0 then -- nil type means CARG(func, ctype). 394 | ins = op1 395 | ctype = formatk(tr, op2) 396 | end 397 | end 398 | if ins < 0 then 399 | out:write(format("[0x%x](", tonumber((tracek(tr, ins))))) 400 | else 401 | out:write(format("%04d (", ins)) 402 | end 403 | return ctype 404 | end 405 | 406 | -- Recursively gather CALL* args and dump them. 407 | local function dumpcallargs(tr, ins) 408 | if ins < 0 then 409 | out:write(formatk(tr, ins)) 410 | else 411 | local m, ot, op1, op2 = traceir(tr, ins) 412 | local oidx = 6*shr(ot, 8) 413 | local op = sub(vmdef.irnames, oidx+1, oidx+6) 414 | if op == "CARG " then 415 | dumpcallargs(tr, op1) 416 | if op2 < 0 then 417 | out:write(" ", formatk(tr, op2)) 418 | else 419 | out:write(" ", format("%04d", op2)) 420 | end 421 | else 422 | out:write(format("%04d", ins)) 423 | end 424 | end 425 | end 426 | 427 | -- Dump IR and interleaved snapshots. 428 | local function dump_ir(tr, dumpsnap, dumpreg) 429 | local info = traceinfo(tr) 430 | if not info then return end 431 | local nins = info.nins 432 | out:write("---- TRACE ", tr, " IR\n") 433 | local irnames = vmdef.irnames 434 | local snapref = 65536 435 | local snap, snapno 436 | if dumpsnap then 437 | snap = tracesnap(tr, 0) 438 | snapref = snap[0] 439 | snapno = 0 440 | end 441 | for ins=1,nins do 442 | if ins >= snapref then 443 | if dumpreg then 444 | out:write(format(".... SNAP #%-3d [ ", snapno)) 445 | else 446 | out:write(format(".... SNAP #%-3d [ ", snapno)) 447 | end 448 | printsnap(tr, snap) 449 | snapno = snapno + 1 450 | snap = tracesnap(tr, snapno) 451 | snapref = snap and snap[0] or 65536 452 | end 453 | local m, ot, op1, op2, ridsp = traceir(tr, ins) 454 | local oidx, t = 6*shr(ot, 8), band(ot, 31) 455 | local op = sub(irnames, oidx+1, oidx+6) 456 | if op == "LOOP " then 457 | if dumpreg then 458 | out:write(format("%04d ------------ LOOP ------------\n", ins)) 459 | else 460 | out:write(format("%04d ------ LOOP ------------\n", ins)) 461 | end 462 | elseif op ~= "NOP " and op ~= "CARG " and 463 | (dumpreg or op ~= "RENAME") then 464 | local rid = band(ridsp, 255) 465 | if dumpreg then 466 | out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins))) 467 | else 468 | out:write(format("%04d ", ins)) 469 | end 470 | out:write(format("%s%s %s %s ", 471 | (rid == 254 or rid == 253) and "}" or 472 | (band(ot, 128) == 0 and " " or ">"), 473 | band(ot, 64) == 0 and " " or "+", 474 | irtype[t], op)) 475 | local m1, m2 = band(m, 3), band(m, 3*4) 476 | if sub(op, 1, 4) == "CALL" then 477 | local ctype 478 | if m2 == 1*4 then -- op2 == IRMlit 479 | out:write(format("%-10s (", vmdef.ircall[op2])) 480 | else 481 | ctype = dumpcallfunc(tr, op2) 482 | end 483 | if op1 ~= -1 then dumpcallargs(tr, op1) end 484 | out:write(")") 485 | if ctype then out:write(" ctype ", ctype) end 486 | elseif op == "CNEW " and op2 == -1 then 487 | out:write(formatk(tr, op1)) 488 | elseif m1 ~= 3 then -- op1 != IRMnone 489 | if op1 < 0 then 490 | out:write(formatk(tr, op1)) 491 | else 492 | out:write(format(m1 == 0 and "%04d" or "#%-3d", op1)) 493 | end 494 | if m2 ~= 3*4 then -- op2 != IRMnone 495 | if m2 == 1*4 then -- op2 == IRMlit 496 | local litn = litname[op] 497 | if litn and litn[op2] then 498 | out:write(" ", litn[op2]) 499 | elseif op == "UREFO " or op == "UREFC " then 500 | out:write(format(" #%-3d", shr(op2, 8))) 501 | else 502 | out:write(format(" #%-3d", op2)) 503 | end 504 | elseif op2 < 0 then 505 | out:write(" ", formatk(tr, op2)) 506 | else 507 | out:write(format(" %04d", op2)) 508 | end 509 | end 510 | end 511 | out:write("\n") 512 | end 513 | end 514 | if snap then 515 | if dumpreg then 516 | out:write(format(".... SNAP #%-3d [ ", snapno)) 517 | else 518 | out:write(format(".... SNAP #%-3d [ ", snapno)) 519 | end 520 | printsnap(tr, snap) 521 | end 522 | end 523 | 524 | ------------------------------------------------------------------------------ 525 | 526 | local recprefix = "" 527 | local recdepth = 0 528 | 529 | -- Format trace error message. 530 | local function fmterr(err, info) 531 | if type(err) == "number" then 532 | if type(info) == "function" then info = fmtfunc(info) end 533 | err = format(vmdef.traceerr[err], info) 534 | end 535 | return err 536 | end 537 | 538 | -- Dump trace states. 539 | local function dump_trace(what, tr, func, pc, otr, oex) 540 | if what == "stop" or (what == "abort" and dumpmode.a) then 541 | if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop") 542 | elseif dumpmode.s then dump_snap(tr) end 543 | if dumpmode.m then dump_mcode(tr) end 544 | end 545 | if what == "start" then 546 | if dumpmode.H then out:write('
\n') end 547 | out:write("---- TRACE ", tr, " ", what) 548 | if otr then out:write(" ", otr, "/", oex) end 549 | out:write(" ", fmtfunc(func, pc), "\n") 550 | elseif what == "stop" or what == "abort" then 551 | out:write("---- TRACE ", tr, " ", what) 552 | if what == "abort" then 553 | out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n") 554 | else 555 | local info = traceinfo(tr) 556 | local link, ltype = info.link, info.linktype 557 | if link == tr or link == 0 then 558 | out:write(" -> ", ltype, "\n") 559 | elseif ltype == "root" then 560 | out:write(" -> ", link, "\n") 561 | else 562 | out:write(" -> ", link, " ", ltype, "\n") 563 | end 564 | end 565 | if dumpmode.H then out:write("\n\n") else out:write("\n") end 566 | else 567 | out:write("---- TRACE ", what, "\n\n") 568 | end 569 | out:flush() 570 | end 571 | 572 | -- Dump recorded bytecode. 573 | local function dump_record(tr, func, pc, depth, callee) 574 | if depth ~= recdepth then 575 | recdepth = depth 576 | recprefix = rep(" .", depth) 577 | end 578 | local line 579 | if pc >= 0 then 580 | line = bcline(func, pc, recprefix) 581 | if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end 582 | else 583 | line = "0000 "..recprefix.." FUNCC \n" 584 | callee = func 585 | end 586 | if pc <= 0 then 587 | out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n") 588 | else 589 | out:write(line) 590 | end 591 | if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC 592 | out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond. 593 | end 594 | end 595 | 596 | ------------------------------------------------------------------------------ 597 | 598 | -- Dump taken trace exits. 599 | local function dump_texit(tr, ex, ngpr, nfpr, ...) 600 | out:write("---- TRACE ", tr, " exit ", ex, "\n") 601 | if dumpmode.X then 602 | local regs = {...} 603 | if jit.arch == "x64" then 604 | for i=1,ngpr do 605 | out:write(format(" %016x", regs[i])) 606 | if i % 4 == 0 then out:write("\n") end 607 | end 608 | else 609 | for i=1,ngpr do 610 | out:write(format(" %08x", regs[i])) 611 | if i % 8 == 0 then out:write("\n") end 612 | end 613 | end 614 | if jit.arch == "mips" or jit.arch == "mipsel" then 615 | for i=1,nfpr,2 do 616 | out:write(format(" %+17.14g", regs[ngpr+i])) 617 | if i % 8 == 7 then out:write("\n") end 618 | end 619 | else 620 | for i=1,nfpr do 621 | out:write(format(" %+17.14g", regs[ngpr+i])) 622 | if i % 4 == 0 then out:write("\n") end 623 | end 624 | end 625 | end 626 | end 627 | 628 | ------------------------------------------------------------------------------ 629 | 630 | -- Detach dump handlers. 631 | local function dumpoff() 632 | if active then 633 | active = false 634 | jit.attach(dump_texit) 635 | jit.attach(dump_record) 636 | jit.attach(dump_trace) 637 | if out and out ~= stdout and out ~= stderr then out:close() end 638 | out = nil 639 | end 640 | end 641 | 642 | -- Open the output file and attach dump handlers. 643 | local function dumpon(opt, outfile) 644 | if active then dumpoff() end 645 | 646 | local colormode = os.getenv("COLORTERM") and "A" or "T" 647 | if opt then 648 | opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end) 649 | end 650 | 651 | local m = { t=true, b=true, i=true, m=true, } 652 | if opt and opt ~= "" then 653 | local o = sub(opt, 1, 1) 654 | if o ~= "+" and o ~= "-" then m = {} end 655 | for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end 656 | end 657 | dumpmode = m 658 | 659 | if m.t or m.b or m.i or m.s or m.m then 660 | jit.attach(dump_trace, "trace") 661 | end 662 | if m.b then 663 | jit.attach(dump_record, "record") 664 | if not bcline then bcline = require("jit.bc").line end 665 | end 666 | if m.x or m.X then 667 | jit.attach(dump_texit, "texit") 668 | end 669 | 670 | if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end 671 | if outfile then 672 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) 673 | else 674 | out = stdout 675 | end 676 | 677 | m[colormode] = true 678 | if colormode == "A" then 679 | colorize = colorize_ansi 680 | irtype = irtype_ansi 681 | elseif colormode == "H" then 682 | colorize = colorize_html 683 | irtype = irtype_html 684 | out:write(header_html) 685 | else 686 | colorize = colorize_text 687 | irtype = irtype_text 688 | end 689 | 690 | active = true 691 | end 692 | 693 | -- Public module functions. 694 | module(...) 695 | 696 | on = dumpon 697 | off = dumpoff 698 | start = dumpon -- For -j command line option. 699 | 700 | -------------------------------------------------------------------------------- /jit/v.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- Verbose mode of the LuaJIT compiler. 3 | -- 4 | -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. 5 | -- Released under the MIT license. See Copyright Notice in luajit.h 6 | ---------------------------------------------------------------------------- 7 | -- 8 | -- This module shows verbose information about the progress of the 9 | -- JIT compiler. It prints one line for each generated trace. This module 10 | -- is useful to see which code has been compiled or where the compiler 11 | -- punts and falls back to the interpreter. 12 | -- 13 | -- Example usage: 14 | -- 15 | -- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end" 16 | -- luajit -jv=myapp.out myapp.lua 17 | -- 18 | -- Default output is to stderr. To redirect the output to a file, pass a 19 | -- filename as an argument (use '-' for stdout) or set the environment 20 | -- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the 21 | -- module is started. 22 | -- 23 | -- The output from the first example should look like this: 24 | -- 25 | -- [TRACE 1 (command line):1 loop] 26 | -- [TRACE 2 (1/3) (command line):1 -> 1] 27 | -- 28 | -- The first number in each line is the internal trace number. Next are 29 | -- the file name ('(command line)') and the line number (':1') where the 30 | -- trace has started. Side traces also show the parent trace number and 31 | -- the exit number where they are attached to in parentheses ('(1/3)'). 32 | -- An arrow at the end shows where the trace links to ('-> 1'), unless 33 | -- it loops to itself. 34 | -- 35 | -- In this case the inner loop gets hot and is traced first, generating 36 | -- a root trace. Then the last exit from the 1st trace gets hot, too, 37 | -- and triggers generation of the 2nd trace. The side trace follows the 38 | -- path along the outer loop and *around* the inner loop, back to its 39 | -- start, and then links to the 1st trace. Yes, this may seem unusual, 40 | -- if you know how traditional compilers work. Trace compilers are full 41 | -- of surprises like this -- have fun! :-) 42 | -- 43 | -- Aborted traces are shown like this: 44 | -- 45 | -- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50] 46 | -- 47 | -- Don't worry -- trace aborts are quite common, even in programs which 48 | -- can be fully compiled. The compiler may retry several times until it 49 | -- finds a suitable trace. 50 | -- 51 | -- Of course this doesn't work with features that are not-yet-implemented 52 | -- (NYI error messages). The VM simply falls back to the interpreter. This 53 | -- may not matter at all if the particular trace is not very high up in 54 | -- the CPU usage profile. Oh, and the interpreter is quite fast, too. 55 | -- 56 | -- Also check out the -jdump module, which prints all the gory details. 57 | -- 58 | ------------------------------------------------------------------------------ 59 | 60 | -- Cache some library functions and objects. 61 | local jit = require("jit") 62 | assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") 63 | local jutil = require("jit.util") 64 | local vmdef = require("jit.vmdef") 65 | local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo 66 | local type, format = type, string.format 67 | local stdout, stderr = io.stdout, io.stderr 68 | 69 | -- Active flag and output file handle. 70 | local active, out 71 | 72 | ------------------------------------------------------------------------------ 73 | 74 | local startloc, startex 75 | 76 | local function fmtfunc(func, pc) 77 | local fi = funcinfo(func, pc) 78 | if fi.loc then 79 | return fi.loc 80 | elseif fi.ffid then 81 | return vmdef.ffnames[fi.ffid] 82 | elseif fi.addr then 83 | return format("C:%x", fi.addr) 84 | else 85 | return "(?)" 86 | end 87 | end 88 | 89 | -- Format trace error message. 90 | local function fmterr(err, info) 91 | if type(err) == "number" then 92 | if type(info) == "function" then info = fmtfunc(info) end 93 | err = format(vmdef.traceerr[err], info) 94 | end 95 | return err 96 | end 97 | 98 | -- Dump trace states. 99 | local function dump_trace(what, tr, func, pc, otr, oex) 100 | if what == "start" then 101 | startloc = fmtfunc(func, pc) 102 | startex = otr and "("..otr.."/"..oex..") " or "" 103 | else 104 | if what == "abort" then 105 | local loc = fmtfunc(func, pc) 106 | if loc ~= startloc then 107 | out:write(format("[TRACE --- %s%s -- %s at %s]\n", 108 | startex, startloc, fmterr(otr, oex), loc)) 109 | else 110 | out:write(format("[TRACE --- %s%s -- %s]\n", 111 | startex, startloc, fmterr(otr, oex))) 112 | end 113 | elseif what == "stop" then 114 | local info = traceinfo(tr) 115 | local link, ltype = info.link, info.linktype 116 | if ltype == "interpreter" then 117 | out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", 118 | tr, startex, startloc)) 119 | elseif link == tr or link == 0 then 120 | out:write(format("[TRACE %3s %s%s %s]\n", 121 | tr, startex, startloc, ltype)) 122 | elseif ltype == "root" then 123 | out:write(format("[TRACE %3s %s%s -> %d]\n", 124 | tr, startex, startloc, link)) 125 | else 126 | out:write(format("[TRACE %3s %s%s -> %d %s]\n", 127 | tr, startex, startloc, link, ltype)) 128 | end 129 | else 130 | out:write(format("[TRACE %s]\n", what)) 131 | end 132 | out:flush() 133 | end 134 | end 135 | 136 | ------------------------------------------------------------------------------ 137 | 138 | -- Detach dump handlers. 139 | local function dumpoff() 140 | if active then 141 | active = false 142 | jit.attach(dump_trace) 143 | if out and out ~= stdout and out ~= stderr then out:close() end 144 | out = nil 145 | end 146 | end 147 | 148 | -- Open the output file and attach dump handlers. 149 | local function dumpon(outfile) 150 | if active then dumpoff() end 151 | if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end 152 | if outfile then 153 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) 154 | else 155 | out = stderr 156 | end 157 | jit.attach(dump_trace, "trace") 158 | active = true 159 | end 160 | 161 | -- Public module functions. 162 | module(...) 163 | 164 | on = dumpon 165 | off = dumpoff 166 | start = dumpon -- For -j command line option. 167 | 168 | -------------------------------------------------------------------------------- /jit/vmdef.lua: -------------------------------------------------------------------------------- 1 | -- This is a generated file. DO NOT EDIT! 2 | 3 | module(...) 4 | 5 | bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF MOV NOT UNM LEN ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW CAT KSTR KCDATAKSHORTKNUM KPRI KNIL UGET USETV USETS USETN USETP UCLO FNEW TNEW TDUP GGET GSET TGETV TGETS TGETB TSETV TSETS TSETB TSETM CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW" 6 | 7 | irnames = "LT GE LE GT ULT UGE ULE UGT EQ NE ABC RETF NOP BASE PVAL GCSTEPHIOP LOOP USE PHI RENAMEKPRI KINT KGC KPTR KKPTR KNULL KNUM KINT64KSLOT BNOT BSWAP BAND BOR BXOR BSHL BSHR BSAR BROL BROR ADD SUB MUL DIV MOD POW NEG ABS ATAN2 LDEXP MIN MAX FPMATHADDOV SUBOV MULOV AREF HREFK HREF NEWREFUREFO UREFC FREF STRREFALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ASTOREHSTOREUSTOREFSTOREXSTORESNEW XSNEW TNEW TDUP CNEW CNEWI TBAR OBAR XBAR CONV TOBIT TOSTR STRTO CALLN CALLL CALLS CALLXSCARG " 8 | 9 | irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "exp", "exp2", "log", "log2", "log10", "sin", "cos", "tan", "other", } 10 | 11 | irfield = { [0]="str.len", "func.env", "func.pc", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", } 12 | 13 | ircall = { 14 | [0]="lj_str_cmp", 15 | "lj_str_new", 16 | "lj_strscan_num", 17 | "lj_str_fromint", 18 | "lj_str_fromnum", 19 | "lj_tab_new1", 20 | "lj_tab_dup", 21 | "lj_tab_newkey", 22 | "lj_tab_len", 23 | "lj_gc_step_jit", 24 | "lj_gc_barrieruv", 25 | "lj_mem_newgco", 26 | "lj_math_random_step", 27 | "lj_vm_modi", 28 | "sinh", 29 | "cosh", 30 | "tanh", 31 | "fputc", 32 | "fwrite", 33 | "fflush", 34 | "lj_vm_floor", 35 | "lj_vm_ceil", 36 | "lj_vm_trunc", 37 | "sqrt", 38 | "exp", 39 | "lj_vm_exp2", 40 | "log", 41 | "lj_vm_log2", 42 | "log10", 43 | "sin", 44 | "cos", 45 | "tan", 46 | "lj_vm_powi", 47 | "pow", 48 | "atan2", 49 | "ldexp", 50 | "lj_vm_tobit", 51 | "softfp_add", 52 | "softfp_sub", 53 | "softfp_mul", 54 | "softfp_div", 55 | "softfp_cmp", 56 | "softfp_i2d", 57 | "softfp_d2i", 58 | "softfp_ui2d", 59 | "softfp_f2d", 60 | "softfp_d2ui", 61 | "softfp_d2f", 62 | "softfp_i2f", 63 | "softfp_ui2f", 64 | "softfp_f2i", 65 | "softfp_f2ui", 66 | "fp64_l2d", 67 | "fp64_ul2d", 68 | "fp64_l2f", 69 | "fp64_ul2f", 70 | "fp64_d2l", 71 | "fp64_d2ul", 72 | "fp64_f2l", 73 | "fp64_f2ul", 74 | "lj_carith_divi64", 75 | "lj_carith_divu64", 76 | "lj_carith_modi64", 77 | "lj_carith_modu64", 78 | "lj_carith_powi64", 79 | "lj_carith_powu64", 80 | "lj_cdata_setfin", 81 | "strlen", 82 | "memcpy", 83 | "memset", 84 | "lj_vm_errno", 85 | "lj_carith_mul64", 86 | } 87 | 88 | traceerr = { 89 | [0]="error thrown or hook called during recording", 90 | "trace too long", 91 | "trace too deep", 92 | "too many snapshots", 93 | "blacklisted", 94 | "NYI: bytecode %d", 95 | "leaving loop in root trace", 96 | "inner loop in root trace", 97 | "loop unroll limit reached", 98 | "bad argument type", 99 | "JIT compilation disabled for function", 100 | "call unroll limit reached", 101 | "down-recursion, restarting", 102 | "NYI: C function %p", 103 | "NYI: FastFunc %s", 104 | "NYI: unsupported variant of FastFunc %s", 105 | "NYI: return to lower frame", 106 | "store with nil or NaN key", 107 | "missing metamethod", 108 | "looping index lookup", 109 | "NYI: mixed sparse/dense table", 110 | "symbol not in cache", 111 | "NYI: unsupported C type conversion", 112 | "NYI: unsupported C function type", 113 | "guard would always fail", 114 | "too many PHIs", 115 | "persistent type instability", 116 | "failed to allocate mcode memory", 117 | "machine code too long", 118 | "hit mcode limit (retrying)", 119 | "too many spill slots", 120 | "inconsistent register allocation", 121 | "NYI: cannot assemble IR instruction %d", 122 | "NYI: PHI shuffling too complex", 123 | "NYI: register coalescing too complex", 124 | } 125 | 126 | ffnames = { 127 | [0]="Lua", 128 | "C", 129 | "assert", 130 | "type", 131 | "next", 132 | "pairs", 133 | "ipairs_aux", 134 | "ipairs", 135 | "getmetatable", 136 | "setmetatable", 137 | "getfenv", 138 | "setfenv", 139 | "rawget", 140 | "rawset", 141 | "rawequal", 142 | "unpack", 143 | "select", 144 | "tonumber", 145 | "tostring", 146 | "error", 147 | "pcall", 148 | "xpcall", 149 | "loadfile", 150 | "load", 151 | "loadstring", 152 | "dofile", 153 | "gcinfo", 154 | "collectgarbage", 155 | "newproxy", 156 | "print", 157 | "coroutine.status", 158 | "coroutine.running", 159 | "coroutine.create", 160 | "coroutine.yield", 161 | "coroutine.resume", 162 | "coroutine.wrap_aux", 163 | "coroutine.wrap", 164 | "math.abs", 165 | "math.floor", 166 | "math.ceil", 167 | "math.sqrt", 168 | "math.log10", 169 | "math.exp", 170 | "math.sin", 171 | "math.cos", 172 | "math.tan", 173 | "math.asin", 174 | "math.acos", 175 | "math.atan", 176 | "math.sinh", 177 | "math.cosh", 178 | "math.tanh", 179 | "math.frexp", 180 | "math.modf", 181 | "math.deg", 182 | "math.rad", 183 | "math.log", 184 | "math.atan2", 185 | "math.pow", 186 | "math.fmod", 187 | "math.ldexp", 188 | "math.min", 189 | "math.max", 190 | "math.random", 191 | "math.randomseed", 192 | "bit.tobit", 193 | "bit.bnot", 194 | "bit.bswap", 195 | "bit.lshift", 196 | "bit.rshift", 197 | "bit.arshift", 198 | "bit.rol", 199 | "bit.ror", 200 | "bit.band", 201 | "bit.bor", 202 | "bit.bxor", 203 | "bit.tohex", 204 | "string.len", 205 | "string.byte", 206 | "string.char", 207 | "string.sub", 208 | "string.rep", 209 | "string.reverse", 210 | "string.lower", 211 | "string.upper", 212 | "string.dump", 213 | "string.find", 214 | "string.match", 215 | "string.gmatch_aux", 216 | "string.gmatch", 217 | "string.gsub", 218 | "string.format", 219 | "table.foreachi", 220 | "table.foreach", 221 | "table.getn", 222 | "table.maxn", 223 | "table.insert", 224 | "table.remove", 225 | "table.concat", 226 | "table.sort", 227 | "io.method.close", 228 | "io.method.read", 229 | "io.method.write", 230 | "io.method.flush", 231 | "io.method.seek", 232 | "io.method.setvbuf", 233 | "io.method.lines", 234 | "io.method.__gc", 235 | "io.method.__tostring", 236 | "io.open", 237 | "io.popen", 238 | "io.tmpfile", 239 | "io.close", 240 | "io.read", 241 | "io.write", 242 | "io.flush", 243 | "io.input", 244 | "io.output", 245 | "io.lines", 246 | "io.type", 247 | "os.execute", 248 | "os.remove", 249 | "os.rename", 250 | "os.tmpname", 251 | "os.getenv", 252 | "os.exit", 253 | "os.clock", 254 | "os.date", 255 | "os.time", 256 | "os.difftime", 257 | "os.setlocale", 258 | "debug.getregistry", 259 | "debug.getmetatable", 260 | "debug.setmetatable", 261 | "debug.getfenv", 262 | "debug.setfenv", 263 | "debug.getinfo", 264 | "debug.getlocal", 265 | "debug.setlocal", 266 | "debug.getupvalue", 267 | "debug.setupvalue", 268 | "debug.upvalueid", 269 | "debug.upvaluejoin", 270 | "debug.sethook", 271 | "debug.gethook", 272 | "debug.debug", 273 | "debug.traceback", 274 | "jit.on", 275 | "jit.off", 276 | "jit.flush", 277 | "jit.status", 278 | "jit.attach", 279 | "jit.util.funcinfo", 280 | "jit.util.funcbc", 281 | "jit.util.funck", 282 | "jit.util.funcuvname", 283 | "jit.util.traceinfo", 284 | "jit.util.traceir", 285 | "jit.util.tracek", 286 | "jit.util.tracesnap", 287 | "jit.util.tracemc", 288 | "jit.util.traceexitstub", 289 | "jit.util.ircalladdr", 290 | "jit.opt.start", 291 | "ffi.meta.__index", 292 | "ffi.meta.__newindex", 293 | "ffi.meta.__eq", 294 | "ffi.meta.__len", 295 | "ffi.meta.__lt", 296 | "ffi.meta.__le", 297 | "ffi.meta.__concat", 298 | "ffi.meta.__call", 299 | "ffi.meta.__add", 300 | "ffi.meta.__sub", 301 | "ffi.meta.__mul", 302 | "ffi.meta.__div", 303 | "ffi.meta.__mod", 304 | "ffi.meta.__pow", 305 | "ffi.meta.__unm", 306 | "ffi.meta.__tostring", 307 | "ffi.meta.__pairs", 308 | "ffi.meta.__ipairs", 309 | "ffi.clib.__index", 310 | "ffi.clib.__newindex", 311 | "ffi.clib.__gc", 312 | "ffi.callback.free", 313 | "ffi.callback.set", 314 | "ffi.cdef", 315 | "ffi.new", 316 | "ffi.cast", 317 | "ffi.typeof", 318 | "ffi.istype", 319 | "ffi.sizeof", 320 | "ffi.alignof", 321 | "ffi.offsetof", 322 | "ffi.errno", 323 | "ffi.string", 324 | "ffi.copy", 325 | "ffi.fill", 326 | "ffi.abi", 327 | "ffi.metatype", 328 | "ffi.gc", 329 | "ffi.load", 330 | } 331 | 332 | -------------------------------------------------------------------------------- /libs/bcread.lua: -------------------------------------------------------------------------------- 1 | local strsub, strbyte = string.sub, string.byte 2 | local bor, band, lshift, rshift = bit.bor, bit.band, bit.lshift, bit.rshift 3 | 4 | local function byte(ls, p) 5 | p = p or ls.p 6 | return strbyte(ls.data, p, p) 7 | end 8 | 9 | local function bcread_consume(ls, len) 10 | for p = ls.p, ls.p + len - 1 do 11 | ls.bytes[#ls.bytes + 1] = byte(ls, p) 12 | end 13 | ls.n = ls.n - len 14 | end 15 | 16 | local function bcread_dec(ls) 17 | local b = byte(ls) 18 | ls.bytes[#ls.bytes + 1] = b 19 | ls.n = ls.n - 1 20 | return b 21 | end 22 | 23 | local function bcread_byte(ls) 24 | local b = bcread_dec(ls) 25 | ls.p = ls.p + 1 26 | return b 27 | end 28 | 29 | local function bcread_uint16(ls) 30 | local a, b = strbyte(ls.data, ls.p, ls.p + 1) 31 | bcread_consume(ls, 2) 32 | ls.p = ls.p + 2 33 | return bor(lshift(b, 8), a) 34 | end 35 | 36 | local function bcread_uleb128(ls) 37 | local v = bcread_byte(ls) 38 | if v >= 0x80 then 39 | local sh = 0 40 | v = band(v, 0x7f) 41 | repeat 42 | local b = bcread_byte(ls) 43 | v = bor(v, lshift(band(b, 0x7f), sh + 7)) 44 | sh = sh + 7 45 | until b < 0x80 46 | end 47 | return v 48 | end 49 | 50 | local function bcread_uleb128_33(ls) 51 | local v = rshift(bcread_byte(ls), 1) 52 | if v >= 0x40 then 53 | local sh = -1 54 | v = band(v, 0x3f) 55 | repeat 56 | sh = sh + 7 57 | local b = bcread_byte(ls) 58 | v = bor(v, lshift(band(b, 0x7f), sh)) 59 | until b < 0x80 60 | end 61 | return v 62 | end 63 | 64 | local function bcread_mem(ls, len) 65 | local s = strsub(ls.data, ls.p, ls.p + len - 1) 66 | bcread_consume(ls, len) 67 | ls.p = ls.p + len 68 | return s 69 | end 70 | 71 | local function bcread_ktabk(ls) 72 | local tp = bcread_uleb128(ls) 73 | if tp == 3 then 74 | bcread_uleb128(ls) 75 | elseif tp == 4 then 76 | bcread_uleb128(ls) 77 | bcread_uleb128(ls) 78 | elseif tp >= 5 then 79 | bcread_mem(ls, tp - 5) 80 | end 81 | end 82 | 83 | local function bcread_kgc(ls, target) 84 | local tp = bcread_uleb128(ls) 85 | if tp >= 5 then 86 | bcread_mem(ls, tp - 5) 87 | elseif tp == 1 then 88 | local narray = bcread_uleb128(ls) 89 | local nhash = bcread_uleb128(ls) 90 | 91 | for i = 1, narray do 92 | bcread_ktabk(ls) 93 | end 94 | 95 | for i = 1, nhash do 96 | bcread_ktabk(ls) 97 | bcread_ktabk(ls) 98 | end 99 | 100 | return narray - 1 101 | elseif tp == 0 then 102 | return table.remove(target.childs) 103 | else 104 | error("kgc type " .. tp) 105 | end 106 | end 107 | 108 | local function bcread_proto(ls, target) 109 | if ls.n > 0 and byte(ls) == 0 then 110 | bcread_byte(ls) 111 | return nil 112 | end 113 | 114 | local proto = { 115 | consts = {}, 116 | upvalues = {}, 117 | } 118 | target.proto = proto 119 | 120 | local len = bcread_uleb128(ls) 121 | local startn = ls.n 122 | 123 | bcread_byte(ls) 124 | bcread_byte(ls) 125 | bcread_byte(ls) 126 | 127 | local sizeuv = bcread_byte(ls) 128 | local sizekgc = bcread_uleb128(ls) 129 | local sizekn = bcread_uleb128(ls) 130 | local sizebc = bcread_uleb128(ls) 131 | 132 | local sizedbg = 0 133 | local not_stripped = band(ls.flags, 2) == 0 134 | if not_stripped then 135 | sizedbg = bcread_uleb128(ls) 136 | if sizedbg ~= 0 then 137 | bcread_uleb128(ls) 138 | bcread_uleb128(ls) 139 | end 140 | end 141 | 142 | for pc = 1, sizebc do 143 | bcread_mem(ls, 4) 144 | end 145 | 146 | for i = 1, sizeuv do 147 | proto.upvalues[i - 1] = bcread_uint16(ls) 148 | end 149 | 150 | for i = 1, sizekgc do 151 | proto.consts[-(sizekgc + 1) + i] = bcread_kgc(ls, target) 152 | end 153 | 154 | for i = 1, sizekn do 155 | local isnumbit = band(byte(ls), 1) 156 | bcread_uleb128_33(ls) 157 | if isnumbit ~= 0 then 158 | bcread_uleb128(ls) 159 | end 160 | end 161 | 162 | if not_stripped and sizedbg ~= 0 then 163 | bcread_mem(ls, sizedbg) 164 | end 165 | 166 | assert(len == startn - ls.n, "prototype bytecode size mismatch") 167 | return target.proto 168 | end 169 | 170 | local function bcread(s) 171 | local ls = {data = s, n = #s, p = 1, bytes = {}} 172 | local target = { 173 | childs = {} 174 | } 175 | 176 | -- header 177 | do 178 | bcread_mem(ls, 3) 179 | bcread_uleb128(ls) 180 | local flags = bcread_uleb128(ls) 181 | if (band(flags, 2) ~= 2) then 182 | bcread_mem(ls, bcread_uleb128(ls)) 183 | end 184 | ls.flags = flags 185 | end 186 | 187 | repeat 188 | local pt = bcread_proto(ls, target) 189 | target.childs[#target.childs + 1] = pt 190 | until not pt 191 | 192 | return target.proto 193 | end 194 | 195 | return bcread -------------------------------------------------------------------------------- /libs/bit.lua: -------------------------------------------------------------------------------- 1 | local bit = require("bit") 2 | local band, bor, bxor, bnot = bit.band, bit.bor, bit.bxor, bit.bnot 3 | local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift 4 | local bswap, tohex = bit.bswap, bit.tohex 5 | 6 | -- ============================================================================================== 7 | -- Constructor and destructuring 8 | -- ============================================================================================== 9 | 10 | -- We must clear the sign because the BitOp library uses signed 32-bit integers. 11 | -- We do so by clearing the sign bit with a logical right shift, and multiplying by 2. 12 | local function U64_join(hi, lo) 13 | local rshift, band = rshift, band 14 | hi = rshift(hi, 1) * 2 + band(hi, 1) 15 | lo = rshift(lo, 1) * 2 + band(lo, 1) 16 | return (hi * 0x100000000) + (lo % 0x100000000) 17 | end 18 | 19 | local function U64_split(x) 20 | return tonumber(x / 0x100000000), tonumber(x % 0x100000000) 21 | end 22 | 23 | -- ============================================================================================== 24 | -- Accessors 25 | -- ============================================================================================== 26 | 27 | local function U64_lo(x) 28 | return tonumber(x % 0x100000000) 29 | end 30 | 31 | local function U64_hi(x) 32 | return tonumber(x / 0x100000000) 33 | end 34 | 35 | -- ============================================================================================== 36 | -- To string conversion 37 | -- ============================================================================================== 38 | 39 | -- tohex checks the # of args, so we must use a vararg for the optional arg. 40 | local function U64_tohex(x, ...) 41 | local hi, lo = U64_split(x) 42 | return tohex(hi, ...) .. tohex(lo, ...) 43 | end 44 | 45 | -- ============================================================================================== 46 | -- Binary operations 47 | -- ============================================================================================== 48 | 49 | -- Binary operation implementation 50 | local function _binop(op, x1, x2, ...) 51 | local hi1, lo1 = U64_split(x1) 52 | local hi2, lo2 = U64_split(x2) 53 | local hi, lo = op(hi1, hi2), op(lo1, lo2) 54 | for n = 1, select("#", ...) do 55 | local hi_n, lo_n = U64_split(select(n, ...)) 56 | hi = op(hi, hi_n) 57 | lo = op(lo, lo_n) 58 | end 59 | return U64_join(hi, lo) 60 | end 61 | 62 | local function U64_band(...) 63 | return _binop(band, ...) 64 | end 65 | 66 | local function U64_bor(...) 67 | return _binop(bor, ...) 68 | end 69 | 70 | local function U64_bxor(...) 71 | return _binop(bxor, ...) 72 | end 73 | 74 | -- ============================================================================================== 75 | -- Unary operations 76 | -- ============================================================================================== 77 | 78 | local function U64_bnot(x) 79 | local hi, lo = U64_split(x) 80 | local bnot = bnot 81 | return U64_join(bnot(hi), bnot(lo)) 82 | end 83 | 84 | local function U64_bswap(x) 85 | local hi, lo = U64_split(x) 86 | return U64_join(bswap(lo), bswap(hi)) -- lo and hi are swapped 87 | end 88 | 89 | -- ============================================================================================== 90 | -- Shifting operations 91 | -- ============================================================================================== 92 | 93 | local function U64_lshift(x, n) 94 | if band(n, 0x3F) == 0 then return x end 95 | local hi, lo = U64_split(x) 96 | if band(n, 0x20) == 0 then 97 | lo, hi = lshift(lo, n), bor(lshift(hi, n), rshift(lo, 32 - n)) 98 | else 99 | lo, hi = 0, lshift(lo, n) 100 | end 101 | return U64_join(hi, lo) 102 | end 103 | 104 | local function U64_rshift(x, n) 105 | if band(n, 0x3F) == 0 then return x end 106 | local hi, lo = U64_split(x) 107 | if band(n, 0x20) == 0 then 108 | lo, hi = bor(rshift(lo, n), lshift(hi, 32 - n)), rshift(hi, n) 109 | else 110 | lo, hi = rshift(hi, n - 32), 0 111 | end 112 | return U64_join(hi, lo) 113 | end 114 | 115 | local function U64_arshift(x, n) 116 | if band(n, 0x3F) == 0 then return x end 117 | local hi, lo = U64_split(x) 118 | if band(n, 0x20) == 0 then 119 | lo, hi = bor(rshift(lo, n), lshift(hi, 32 - n)), arshift(hi, n) 120 | else 121 | lo, hi = arshift(hi, n - 32), arshift(hi, 31) 122 | end 123 | return U64_join(hi, lo) 124 | end 125 | 126 | local function U64_rol(x, n) 127 | if band(n, 0x3F) == 0 then return x end 128 | local hi, lo = U64_split(x) 129 | if band(n, 0x20) ~= 0 then 130 | lo, hi = hi, lo 131 | end 132 | if band(n, 0x1F) ~= 0 then 133 | lo, hi = bor(lshift(lo, n), rshift(hi, 32 - n)), bor(lshift(hi, n), rshift(lo, 32 - n)) 134 | end 135 | return U64_join(hi, lo) 136 | end 137 | -- On my machine, the above version was ~3x faster than the one-liner: 138 | -- return U64_bor(U64_lshift(x, n), U64_rshift(x, 64 - n)) 139 | 140 | local function U64_ror(x, n) 141 | return U64_rol(x, 64 - n) 142 | end 143 | 144 | -- ============================================================================================== 145 | -- Library definition 146 | -- ============================================================================================== 147 | 148 | return { 149 | split = U64_split, 150 | join = U64_join, 151 | hi = U64_hi, 152 | lo = U64_lo, 153 | band = U64_band, 154 | bor = U64_bor, 155 | bxor = U64_bxor, 156 | bnot = U64_bnot, 157 | lshift = U64_lshift, 158 | rshift = U64_rshift, 159 | arshift = U64_arshift, 160 | rol = U64_rol, 161 | ror = U64_ror, 162 | bswap = U64_bswap, 163 | tohex = U64_tohex, 164 | } -------------------------------------------------------------------------------- /libs/dis_bc.lua: -------------------------------------------------------------------------------- 1 | -- I'm pretty sure I got this file from Lapin https://github.com/ExtReMLapin 2 | jit.util = jit.util or require("jit.util") 3 | 4 | local disassemble_function 5 | 6 | local OPNAMES = {} 7 | local bcnames = require("jit.vmdef").bcnames 8 | local INST = {} 9 | 10 | do 11 | local i = 0 12 | 13 | for str in bcnames:gmatch"......" do 14 | str = str:gsub("%s", "") 15 | OPNAMES[i] = str 16 | INST[str] = i 17 | i = i + 1 18 | end 19 | end 20 | 21 | _G.OPNAMES = OPNAMES 22 | _G.INST = INST 23 | 24 | assert(INST.ISLT == 0) 25 | 26 | local BCMode = { 27 | -- for the robots 28 | BCMnone = 0, 29 | BCMdst = 1, 30 | BCMbase = 2, 31 | BCMvar = 3, 32 | BCMrbase = 4, 33 | BCMuv = 5, 34 | BCMlit = 6, 35 | BCMlits = 7, 36 | BCMpri = 8, 37 | BCMnum = 9, 38 | BCMstr = 10, 39 | BCMtab = 11, 40 | BCMfunc = 12, 41 | BCMjump = 13, 42 | BCMcdata = 14, 43 | BCM_max = 15, 44 | -- for the human 45 | [0] = "BCMnone", 46 | [1] = "BCMdst", 47 | [2] = "BCMbase", 48 | [3] = "BCMvar", 49 | [4] = "BCMrbase", 50 | [5] = "BCMuv", 51 | [6] = "BCMlit", 52 | [7] = "BCMlits", 53 | [8] = "BCMpri", 54 | [9] = "BCMnum", 55 | [10] = "BCMstr", 56 | [11] = "BCMtab", 57 | [12] = "BCMfunc", 58 | [13] = "BCMjump", 59 | [14] = "BCMcdata", 60 | [15] = "BCM_max" 61 | } 62 | 63 | local jumps = { 64 | -- UCLO = true, 65 | ISNEXT = true, 66 | JMP = true, 67 | -- LOOP = true 68 | } 69 | 70 | local modes_actions = { 71 | A = { 72 | 73 | }, 74 | B = { 75 | 76 | }, 77 | C = { 78 | BCMlits = function(ins, n) 79 | if ins.D > 32767 then 80 | ins.D = ins.D - 65536 81 | end 82 | end, 83 | BCMnum = function(ins, n) 84 | if ins.OP == "TSETM" then 85 | local d = ins.proto.consts[ins.D] 86 | ins.D = d - 2 ^ 52 87 | end 88 | end, 89 | BCMfunc = function(ins, n) 90 | local proto = ins.proto 91 | local consts = proto.consts 92 | ins.D = disassemble_function(consts[-ins.D - 1]) 93 | ins.D.parent = ins.proto 94 | end, 95 | BCMjump = function(ins, n) 96 | local pos = ins.D - 0x7fff + n 97 | ins.D = pos 98 | ins.proto.targets[pos] = true 99 | if jumps[ins.OP] then 100 | ins.OP = "JMP" 101 | end 102 | end, 103 | } 104 | } 105 | 106 | local do_mode_action = function(instruction, n) 107 | local fn 108 | fn = modes_actions.A[BCMode[instruction.CODE.A]] 109 | if fn then fn(instruction, n) end 110 | fn = modes_actions.B[BCMode[instruction.CODE.B]] 111 | if fn then fn(instruction, n) end 112 | fn = modes_actions.C[BCMode[instruction.CODE.C]] 113 | if fn then fn(instruction, n) end 114 | end 115 | 116 | disassemble_function = function(fn) 117 | assert(fn, "function expected") 118 | 119 | local fn_data = jit.util.funcinfo(fn) 120 | assert(fn_data.loc, "expected a Lua function, not a C one") 121 | 122 | local proto = { 123 | slots = fn_data.stackslots, 124 | params = fn_data.params, 125 | vararg = fn_data.isvararg, 126 | upvalues = {}, 127 | consts = {}, 128 | targets = {}, 129 | } 130 | 131 | local upvalues = proto.upvalues 132 | for i = 0, fn_data.upvalues do 133 | upvalues[i] = jit.util.funcuvid(fn, i) 134 | end 135 | 136 | local consts = proto.consts 137 | do 138 | local n_consts = fn_data.nconsts 139 | local n = n_consts - 1 140 | 141 | local value = jit.util.funck(fn, n) 142 | while value ~= nil do 143 | consts[n] = value 144 | n = n - 1 145 | value = jit.util.funck(fn, n) 146 | end 147 | 148 | proto.consts = consts 149 | end 150 | 151 | -- instructions 152 | do 153 | local n_BC = fn_data.bytecodes 154 | local n = 1 155 | 156 | local instructions = {} 157 | while n < n_BC do 158 | local ins, mode = jit.util.funcbc(fn, n) 159 | local mode_a, mode_b, mode_c = bit.band(mode, 7), bit.rshift(bit.band(mode, 15 * 8),3),bit.rshift(bit.band(mode, 15 * 128),7) 160 | 161 | local instruction = { 162 | proto = proto, 163 | OP = OPNAMES[bit.band(ins, 0xff)], 164 | CODE = { 165 | A = mode_a, 166 | B = mode_b, 167 | C = mode_c 168 | }, 169 | C = bit.rshift(bit.band(ins, 0x00ff0000), 16), 170 | B = bit.rshift(ins, 24), 171 | A = bit.rshift(bit.band(ins, 0x0000ff00), 8), 172 | D = bit.rshift(ins, 16), 173 | } 174 | 175 | do_mode_action(instruction, n) 176 | -- print(instruction.OP) 177 | 178 | instructions[n] = instruction 179 | n = n + 1 180 | end 181 | 182 | proto.instructions = instructions 183 | end 184 | 185 | return proto 186 | end 187 | 188 | return disassemble_function -------------------------------------------------------------------------------- /lua51.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/lua51.dll -------------------------------------------------------------------------------- /luajit.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Srlion/lua_obfuscator/5057d7bf80f91a3eb6e4c87fee7ac594f5d0883b/luajit.exe -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | math.randomseed(tostring(function() end):sub(11)) 2 | 3 | package.path = ".\\?.lua" 4 | 5 | local string = string 6 | local sub, find, format = string.sub, string.find, string.format 7 | 8 | local use_utf8 9 | 10 | local conditionals = { 11 | "ISLT", "ISGE", "ISLE", "ISGT", "ISEQV", "ISNEV", 12 | "ISEQS", "ISNES", "ISEQN", "ISNEN", "ISEQP", "ISNEP", 13 | "ISTC", "ISFC", "IST", "ISF"; 14 | "FORI"; "FORL", "ITERL" 15 | } 16 | for i = 1, #conditionals do 17 | local v = conditionals[i] 18 | conditionals[v], conditionals[i] = true, nil 19 | end 20 | local loops = { 21 | FORI = true, 22 | FORL = true, 23 | ITERL = true, 24 | } 25 | local returns = { 26 | RET = true, 27 | RET0 = true, 28 | RET1 = true, 29 | RETM = true, 30 | CALLMT = true, 31 | CALLT = true, 32 | } 33 | 34 | function table.Shuffle(tbl) 35 | for i = #tbl, 2, -1 do 36 | local j = math.random(i) 37 | tbl[i], tbl[j] = tbl[j], tbl[i] 38 | end 39 | 40 | return tbl 41 | end 42 | 43 | function string.tohex(str) 44 | str = str:gsub(".", function(c) return format("\\x%02X", c:byte()) end) 45 | return str 46 | end 47 | 48 | function string.Explode(separator, str, withpattern) 49 | if withpattern == nil then 50 | withpattern = false 51 | end 52 | local ret = {} 53 | local current_pos = 1 54 | for i = 1, #str do 55 | local start_pos, end_pos = find(str, separator, current_pos, not withpattern) 56 | if (not start_pos) then break end 57 | ret[i] = sub(str, current_pos, start_pos - 1) 58 | current_pos = end_pos + 1 59 | end 60 | ret[#ret + 1] = sub(str, current_pos) 61 | if ret[#ret] == "" then 62 | table.remove(ret) 63 | end 64 | return ret 65 | end 66 | 67 | ------------------------------------------------------------------------------ 68 | 69 | local Parser = {} 70 | Parser.__index = Parser 71 | 72 | local to_lua_num; do 73 | local hex_number = function(v) 74 | local neg = v < 0 75 | if neg then 76 | v = math.abs(v) 77 | end 78 | if math.floor(v) == v and v <= 0xffffffff then 79 | v = "0x" .. string.format("%x", v) 80 | end 81 | if neg then 82 | v = "-" .. v 83 | end 84 | return v 85 | end 86 | 87 | local prime_dactors = function(n, ret) 88 | ret = ret or {hex_number(1)} 89 | 90 | while (n % 2 == 0) do 91 | table.insert(ret, hex_number(2)) 92 | n = n / 2 93 | end 94 | 95 | local i = 3 96 | while i <= math.sqrt(n) do 97 | while (n % i == 0) do 98 | table.insert(ret, hex_number(i)) 99 | n = n / i 100 | end 101 | 102 | i = i + 2 103 | end 104 | 105 | if n > 2 then 106 | table.insert(ret, hex_number(n)) 107 | end 108 | 109 | return table.concat(table.Shuffle(ret), "*") 110 | end 111 | 112 | to_lua_num = function(v) 113 | if v == 0 then 114 | return "(" .. prime_dactors(math.random(300, 400), {hex_number(0)}) .. ")" 115 | end 116 | 117 | if v < 0 then 118 | return "-(" .. prime_dactors(math.abs(v)) .. ")" 119 | end 120 | 121 | return "(" .. prime_dactors(v) .. ")" 122 | end 123 | end 124 | 125 | local get_pri = function(v) 126 | if v == 1 or v == false then 127 | return "!!!1" 128 | elseif v == 2 or v == true then 129 | return "!!1" 130 | elseif v == 0 then 131 | return "nil" 132 | end 133 | error("wtf") 134 | end 135 | 136 | local end_condition = false 137 | local OPS; OPS = { 138 | ISLT = function(s, A, B, C, D) 139 | s:writef("if(%s<%s)then ", s:get_var(A), s:get_var(D)) 140 | end, 141 | ISGE = function(s, A, B, C, D) 142 | s:writef("if(%s>=%s)then ", s:get_var(A), s:get_var(D)) 143 | end, 144 | ISLE = function(s, A, B, C, D) 145 | s:writef("if(%s<=%s)then ", s:get_var(A), s:get_var(D)) 146 | end, 147 | ISGT = function(s, A, B, C, D) 148 | s:writef("if(%s>%s)then ", s:get_var(A), s:get_var(D)) 149 | end, 150 | ISEQV = function(s, A, B, C, D) 151 | s:writef("if(%s==%s)then ", s:get_var(A), s:get_var(D)) 152 | end, 153 | ISNEV = function(s, A, B, C, D) 154 | s:writef("if(%s~=%s)then ", s:get_var(A), s:get_var(D)) 155 | end, 156 | ISEQS = function(s, A, B, C, D) 157 | s:writef("if(%s==%s)then ", s:get_var(A), s:str(D)) 158 | end, 159 | ISNES = function(s, A, B, C, D) 160 | s:writef("if(%s~=%s)then ", s:get_var(A), s:str(D)) 161 | end, 162 | ISEQN = function(s, A, B, C, D) 163 | s:writef("if(%s==%s)then ", s:get_var(A), s:num(D)) 164 | end, 165 | ISNEN = function(s, A, B, C, D) 166 | s:writef("if(%s~=%s)then ", s:get_var(A), s:num(D)) 167 | end, 168 | ISEQP = function(s, A, B, C, D) 169 | s:writef("if(%s==%s)then ", s:get_var(A), get_pri(D)) 170 | end, 171 | ISNEP = function(s, A, B, C, D) 172 | s:writef("if(%s~=%s)then ", s:get_var(A), get_pri(D)) 173 | end, 174 | ISTC = function(s, A, B, C, D) 175 | D = s:get_var(D) 176 | s:writef([[if(%s)then ]], D) 177 | s:set_var(A, D) 178 | end, 179 | ISFC = function(s, A, B, C, D) 180 | D = s:get_var(D) 181 | s:writef([[if(!%s)then ]], D) 182 | s:set_var(A, D) 183 | end, 184 | IST = function(s, A, B, C, D) 185 | s:writef("if(%s)then ", s:get_var(D)) 186 | end, 187 | ISF = function(s, A, B, C, D) 188 | s:writef("if(!%s)then ", s:get_var(D)) 189 | end, 190 | MOV = function(s, A, B, C, D, ...) 191 | s:set_var(A, s:get_var(D)) 192 | end, 193 | NOT = function(s, A, B, C, D) 194 | s:set_var(A, "!" .. s:get_var(D)) 195 | end, 196 | UNM = function(s, A, B, C, D) 197 | s:set_var(A, "-" .. s:get_var(D)) 198 | end, 199 | LEN = function(s, A, B, C, D) 200 | s:set_var(A, "#" .. s:get_var(D)) 201 | end, 202 | ADDVN = function(s, A, B, C, D) 203 | s:set_var(A, s:get_var(B) .. "+" .. s:num(C)) 204 | end, 205 | SUBVN = function(s, A, B, C, D) 206 | s:set_var(A, s:get_var(B) .. "-" .. s:num(C)) 207 | end, 208 | MULVN = function(s, A, B, C, D) 209 | s:set_var(A, s:get_var(B) .. "*" .. s:num(C)) 210 | end, 211 | DIVVN = function(s, A, B, C, D) 212 | s:set_var(A, s:get_var(B) .. "/" .. s:num(C)) 213 | end, 214 | MODVN = function(s, A, B, C, D) 215 | s:set_var(A, s:get_var(B) .. "%" .. s:num(C)) 216 | end, 217 | ADDNV = function(s, A, B, C, D) 218 | s:set_var(A, s:num(C) .. "+" .. s:get_var(B)) 219 | end, 220 | SUBNV = function(s, A, B, C, D) 221 | s:set_var(A, s:num(C) .. "-" .. s:get_var(B)) 222 | end, 223 | MULNV = function(s, A, B, C, D) 224 | s:set_var(A, s:num(C) .. "*" .. s:get_var(B)) 225 | end, 226 | DIVNV = function(s, A, B, C, D) 227 | s:set_var(A, s:num(C) .. "/" .. s:get_var(B)) 228 | end, 229 | MODNV = function(s, A, B, C, D) 230 | s:set_var(A, s:num(C) .. "%" .. s:get_var(B)) 231 | end, 232 | ADDVV = function(s, A, B, C, D) 233 | s:set_var(A, s:get_var(B) .. "+" .. s:get_var(C)) 234 | end, 235 | SUBVV = function(s, A, B, C, D) 236 | s:set_var(A, s:get_var(B) .. "-" .. s:get_var(C)) 237 | end, 238 | MULVV = function(s, A, B, C, D) 239 | s:set_var(A, s:get_var(B) .. "*" .. s:get_var(C)) 240 | end, 241 | DIVVV = function(s, A, B, C, D) 242 | s:set_var(A, s:get_var(B) .. "/" .. s:get_var(C)) 243 | end, 244 | MODVV = function(s, A, B, C, D) 245 | s:set_var(A, s:get_var(B) .. "%" .. s:get_var(C)) 246 | end, 247 | POW = function(s, A, B, C, D) 248 | s:set_var(A, s:get_var(B) .. "^" .. s:get_var(C)) 249 | end, 250 | CAT = function(s, A, B, C, D) 251 | local cat_tbl = {} 252 | for i = B, C do 253 | table.insert(cat_tbl, s:get_var(i)) 254 | end 255 | s:set_var(A, table.concat(cat_tbl, "..")) 256 | end, 257 | KSTR = function(s, A, B, C, D) 258 | s:set_var(A, s:str(D)) 259 | end, 260 | KSHORT = function(s, A, B, C, D) 261 | s:set_var(A, to_lua_num(D)) 262 | end, 263 | KNUM = function(s, A, B, C, D) 264 | s:set_var(A, s:num(D)) 265 | end, 266 | KPRI = function(s, A, B, C, D) 267 | s:set_var(A, get_pri(D)) 268 | end, 269 | KNIL = function(s, A, B, C, D) 270 | for i = A, D do 271 | s:set_var(i, "nil") 272 | end 273 | end, 274 | UGET = function(s, A, B, C, D) 275 | s:set_var(A, s:get_uv(D)) 276 | end, 277 | USETV = function(s, A, B, C, D) 278 | s:set_uv(A, s:get_var(D)) 279 | end, 280 | USETS = function(s, A, B, C, D) 281 | s:set_uv(A, s:str(D)) 282 | end, 283 | USETN = function(s, A, B, C, D) 284 | s:set_uv(A, s:num(D)) 285 | end, 286 | USETP = function(s, A, B, C, D) 287 | s:set_uv(A, get_pri(D)) 288 | end, 289 | UCLO = function(s, A, B, C, D, op, pc) 290 | OPS["JMP"](s, A, B, C, D, op, pc) 291 | if returns[s.proto.instructions[pc + 1].OP] then return end 292 | 293 | local slots = s.proto.slots 294 | for i = A, slots do 295 | if s.vars[i] and not s:get_uv(i) then 296 | s.mangled_vars[i] = i + slots + 1 297 | end 298 | end 299 | end, 300 | FNEW = function(s, A, B, C, D) 301 | local p = Parser.new(D, s) 302 | local body = "function(%s)%send" 303 | local params = {} 304 | for i = 0, D.params - 1 do 305 | p.vars[i] = 0 306 | table.insert(params, p:get_var(i)) 307 | end 308 | if D.vararg then 309 | table.insert(params, "...") 310 | end 311 | body = body:format(table.concat(params, ","), p:loop()) 312 | s.last_fnew = s:set_var(A, body) 313 | end, 314 | TNEW = function(s, A, B, C, D) 315 | s.table_values = {} 316 | s.last_array = {} 317 | s.table_pos = s:set_var(A, "{}") 318 | s.last_table_set = s.table_pos 319 | end, 320 | TDUP = function(s, A, B, C, D) 321 | D = s:const(D) 322 | 323 | s.table_values = {} 324 | local t = {} 325 | local _array = {} 326 | for i = 1, #D do 327 | _array[i] = true 328 | t[i] = s:get_value(D[i], true) 329 | D[i] = nil 330 | end 331 | for k, v in pairs(D) do 332 | table.insert(t, "[" .. s:get_value(k) .. "]=" .. s:get_value(v)) 333 | end 334 | table.insert(t, "") 335 | s.last_array = _array 336 | s.table_pos = s:set_var(A, "{" .. table.concat(t, ";") .. "}") 337 | s.last_table_set = s.table_pos 338 | end, 339 | GGET = function(s, A, B, C, D) 340 | s:set_var(A, s:str(D, true)) 341 | end, 342 | GSET = function(s, A, B, C, D) 343 | s:writef("%s=%s;", s:str(D, true), s:get_var(A)) 344 | end, 345 | TGETV = function(s, A, B, C, D) 346 | s:set_var(A, format("%s[%s]", s:get_var(B), s:get_var(C))) 347 | end, 348 | TGETS = function(s, A, B, C, D) 349 | s:set_var(A, format("%s[%s]", s:get_var(B), s:str(C))) 350 | end, 351 | TGETB = function(s, A, B, C, D) 352 | s:set_var(A, format("%s[%s]", s:get_var(B), to_lua_num(C))) 353 | end, 354 | TSETV = function(s, A, B, C, D) 355 | local i = s:writef("%s[%s] = %s;", s:get_var(B), s:get_var(C), s:get_var(A)) 356 | table.insert(s.table_values, {s:get_var(B), s:get_var(C), s:get_var(A), i}) 357 | s.last_table_set = i 358 | end, 359 | TSETS = function(s, A, B, C, D) 360 | local i = s:writef("%s[%s] = %s;", s:get_var(B), s:str(C), s:get_var(A)) 361 | s.last_table_set = i 362 | end, 363 | TSETB = function(s, A, B, C, D) 364 | local i = s:writef("%s[%s] = %s;", s:get_var(B), to_lua_num(C), s:get_var(A)) 365 | table.insert(s.table_values, {s:get_var(B), to_lua_num(C), s:get_var(A), i, true}) 366 | s.last_table_set = i 367 | end, 368 | TSETM = function(s, A, B, C, D) 369 | -- problems: 370 | --[[ 371 | local s = {[2] = 3, math.abs(1)} 372 | will output 373 | { 374 | [1] = 1 375 | } 376 | instead of 377 | { 378 | [1] = 1, 379 | [2] = 3 380 | } 381 | thats because i don't know the size of function returns 382 | and if im going to fix it, it will be a lot more inefficient 383 | ]] 384 | local output = s.output 385 | local last_op = s.last_op 386 | local last_call 387 | if last_op ~= "VARG" then 388 | last_call = output[#output] 389 | output[#output] = "" 390 | local str = "" 391 | for i = s.last_table_set + 1, #output - 1 do 392 | str = str .. output[i] 393 | output[i] = "" 394 | end 395 | output[s.table_pos] = str .. output[s.table_pos] 396 | end 397 | 398 | local table_values = s.table_values 399 | local table_output = output[s.table_pos]:sub(1, -3) 400 | 401 | for i = 1, D - 1 do 402 | if not s.last_array[i] then 403 | table_output = table_output .. "nil;" 404 | end 405 | end 406 | 407 | do 408 | local ex = (";"):Explode(table_output:sub(table_output:find("{") + 1), false) 409 | 410 | for i = D, math.huge do 411 | if not ex[i] then break end 412 | ex[i] = "" 413 | end 414 | 415 | ::rep:: 416 | for i = 1, #ex do 417 | if ex[i] == "" then 418 | table.remove(ex, i) 419 | goto rep 420 | end 421 | end 422 | table.insert(ex, "") 423 | table_output = table_output:sub(1, table_output:find("{")) .. table.concat(ex, ";") 424 | end 425 | 426 | for i = 1, #table_values do 427 | local v = table_values[i] 428 | local str 429 | if v[5] then 430 | if tonumber((v[2]:gsub("%W", ""))) >= D then 431 | str = "" 432 | else 433 | str = format([[%s[%s]=%s;]], v[1], v[2], v[3]) 434 | end 435 | else 436 | str = format([[ 437 | if tonumber(%s)&& %s+0>=%s then 438 | else 439 | %s[%s]=%s;end 440 | ]], v[2], v[2], D, v[1], v[2], v[3]) 441 | end 442 | output[v[4]] = str:gsub("\n", " ") 443 | end 444 | 445 | if last_op == "VARG" then 446 | table_output = table_output .. "...;};" 447 | else 448 | output[#output] = "" 449 | table_output = table_output .. last_call:sub(1, -2) .. ";};" 450 | end 451 | 452 | -- s:write(table_output) 453 | output[s.table_pos] = table_output 454 | end, 455 | CALLM = function(s, A, B, C, D) 456 | local last_op = s.last_op 457 | local last_call 458 | if last_op ~= "VARG" then 459 | last_call = s.output[s.last_call] 460 | s.output[s.last_call] = "" 461 | end 462 | 463 | local amt = (B or 1) - 1 464 | local MULTRES = amt == -1 465 | if not MULTRES then 466 | local st, en = A, A + amt - 1 467 | for i = st, en do 468 | s:set_var(i) 469 | if i < en then 470 | s:write(",") 471 | else 472 | s:write("=") 473 | end 474 | end 475 | end 476 | 477 | local str = s:get_var(A) .. "(" 478 | local t = {} 479 | for i = A + 1, A + C do 480 | table.insert(t, s:get_var(i)) 481 | end 482 | if last_op == "VARG" then 483 | table.insert(t, "...);") 484 | else 485 | table.insert(t, last_call:sub(1, -2) .. ");") 486 | end 487 | s.last_call = s:write(str .. table.concat(t, ",")) 488 | end, 489 | CALL = function(s, A, B, C, D) 490 | local amt = (B or 1) - 1 491 | local MULTRES = amt == -1 492 | if not MULTRES then 493 | local st, en = A, A + amt - 1 494 | for i = st, en do 495 | s:set_var(i) 496 | if i < en then 497 | s:write(",") 498 | else 499 | s:write("=") 500 | end 501 | end 502 | end 503 | 504 | local str = s:get_var(A) .. "(" 505 | local t = {} 506 | for i = A + 1, A + C - 1 do 507 | table.insert(t, s:get_var(i)) 508 | end 509 | s.last_call = s:write(str .. table.concat(t, ",") .. ");") 510 | end, 511 | CALLMT = function(s, ...) 512 | s:write("do return ") 513 | OPS["CALLM"](s, ...) 514 | s:write("end;") 515 | end, 516 | CALLT = function(s, ...) 517 | s:write("do return ") 518 | OPS["CALL"](s, ...) 519 | s:write("end;") 520 | end, 521 | ITERC = function(s, A, B, C, D) 522 | s:set_var(A, s:get_var(A - 3)) 523 | s:set_var(A + 1, s:get_var(A - 2)) 524 | s:set_var(A + 2, s:get_var(A - 1)) 525 | 526 | local st, en = A, A + B - 2 527 | for i = st, en do 528 | s:set_var(i) 529 | if i < en then 530 | s:write(",") 531 | else 532 | s:write("=") 533 | end 534 | end 535 | 536 | s:writef([[%s(%s,%s);]], s:get_var(A), s:get_var(A + 1), s:get_var(A + 2)) 537 | end, 538 | RETM = function(s, A, B, C, D) 539 | local last_op = s.last_op 540 | local last_call 541 | if last_op ~= "VARG" then 542 | last_call = s.output[s.last_call] 543 | s.output[s.last_call] = "" 544 | end 545 | s:write("do return ") 546 | 547 | local rets = {} 548 | for i = A, A + D - 1 do 549 | table.insert(rets, s:get_var(i)) 550 | end 551 | if last_op == "VARG" then 552 | table.insert(rets, "...") 553 | else 554 | table.insert(rets, last_call:sub(1, -2)) 555 | end 556 | s:write(table.concat(rets, ",")) 557 | s:write("end;") 558 | end, 559 | RET = function(s, A, B, C, D) 560 | s:write("do return ") 561 | local rets = {} 562 | for i = A, A + D - 2 do 563 | table.insert(rets, s:get_var(i)) 564 | end 565 | s:write(table.concat(rets, ",")) 566 | s:write(";") 567 | s:write("end;") 568 | end, 569 | RET0 = function(s) 570 | s:write("do return;end;") 571 | end, 572 | RET1 = function(s, A, B, C, D) 573 | s:writef("do return %s;end;", s:get_var(A)) 574 | end, 575 | FORI = function(s, A, B, C, D) 576 | local start = s:get_var(A) 577 | local stop = s:get_var(A + 1) 578 | local step = s:get_var(A + 2) 579 | 580 | local i_iter = A + 3 581 | s:set_var(i_iter, start) 582 | 583 | s:writef([[if(!(%s<=0)&& !(%s<=%s))||(!(%s>=0)&& !(%s>=%s))then ]], step, s:get_var(i_iter), stop, step, s:get_var(i_iter), stop, s:get_var(D)) 584 | end, 585 | FORL = function(s, A, B, C, D) 586 | local stop = s:get_var(A + 1) 587 | local step = s:get_var(A + 2) 588 | 589 | local i_iter = A + 3 590 | s:set_var(i_iter, s:get_var(i_iter) .. "+" .. step) 591 | 592 | s:writef([[if(!(%s<=0)&& !(%s>%s))||(!(%s>=0)&& !(%s<%s))then ]], step, s:get_var(i_iter), stop, step, s:get_var(i_iter), stop, s:get_var(D)) 593 | end, 594 | ITERL = function(s, A, B, C, D) 595 | s:writef([[if(%s)then ]], s:get_var(A)) 596 | s:set_var(A - 1, s:get_var(A)) 597 | end, 598 | VARG = function(s, A, B, C, D) 599 | local amt = B - 1 600 | if amt == -1 then 601 | return 602 | end 603 | local t = {} 604 | for i = A, A + amt - 1 do 605 | table.insert(t, s:get_var(i)) 606 | end 607 | if #t > 0 then 608 | s:writef("local %s=...", table.concat(t, ",")) 609 | end 610 | end, 611 | JMP = function(s, A, B, C, D, op, pc) 612 | if pc + 1 == D and s.proto.targets[pc + 1] and not s.used_targets[D] then 613 | s.skip_target = true 614 | elseif not returns[s.last_op] then 615 | s:write("goto ") 616 | s:write(s:get_var(D)) 617 | s:write(";") 618 | s.used_targets[D] = true 619 | end 620 | 621 | if end_condition then 622 | s:write("end;") 623 | end_condition = false 624 | 625 | s:end_scope() 626 | s:start_scope("do ") 627 | end 628 | end, 629 | LOOP = function() 630 | end 631 | } 632 | OPS.ITERN = OPS.ITERC 633 | 634 | function Parser:write(v) 635 | local n = #self.output + 1 636 | self.output[n] = v 637 | return n 638 | end 639 | 640 | function Parser:writef(v, ...) 641 | return self:write(format(v, ...)) 642 | end 643 | 644 | function Parser:start_scope(v) 645 | self.scope = self.scope + 1 646 | self:write(v) 647 | end 648 | 649 | function Parser:end_scope(v) 650 | if self.scope == 0 then return end 651 | self.scope = self.scope - 1 652 | self:write("end;") 653 | end 654 | 655 | local emojis = { 656 | "˝", 657 | "ˢ", 658 | "ˏ", 659 | "˛", 660 | "˵", 661 | "૰", 662 | "೭" 663 | } 664 | local random = function() 665 | math.randomseed(tostring(function() end):sub(11)) 666 | return emojis[math.random(1, #emojis)] 667 | end 668 | function Parser:get_var(k) 669 | k = self.mangled_vars[k] or k 670 | 671 | if not use_utf8 then 672 | return "var" .. self.id .. k 673 | end 674 | 675 | local id = self.id .. k 676 | if type(k) == "number" then 677 | local en = k + 1 678 | k = "" 679 | for i = 1, en do 680 | k = k .. random() 681 | end 682 | else 683 | error("Wtf") 684 | end 685 | 686 | local name = self.var_names[id] 687 | if not name then 688 | name = string.rep("", self.id) .. k 689 | self.var_names[id] = name 690 | end 691 | 692 | return name 693 | end 694 | 695 | function Parser:set_var(k, v) 696 | k = self.mangled_vars[k] or k 697 | 698 | if not self.vars[k] then 699 | self.vars[k] = true 700 | end 701 | 702 | local str = self:get_var(k) 703 | 704 | if v then 705 | str = str .. "=" .. tostring(v) .. ";" 706 | end 707 | 708 | return self:write(str) 709 | end 710 | 711 | function Parser:get_uv(uv) 712 | local i = self.proto.upvalues[uv] 713 | if not i then return end 714 | while i < 32768 do 715 | self = self.parent 716 | i = self.proto.upvalues[i] 717 | end 718 | return self.parent:get_var(i % 16384) 719 | end 720 | 721 | function Parser:set_uv(uv, v) 722 | self:write(self:get_uv(uv)) 723 | self:write("=") 724 | self:write(v .. ";") 725 | end 726 | 727 | function Parser:const(i) 728 | local consts = self.proto.consts 729 | return consts[-i - 1] 730 | end 731 | 732 | function Parser:new_str(v) 733 | v = tostring(v) 734 | v = v:tohex() 735 | return "'" .. v .. "'" 736 | end 737 | 738 | function Parser:str(i, no_mangle) 739 | return no_mangle and self:const(i) or self:new_str(self:const(i)) 740 | end 741 | 742 | function Parser:num(i) 743 | return to_lua_num(self.proto.consts[i]) 744 | end 745 | 746 | function Parser:get_value(v, allow_nil) 747 | local t = type(v) 748 | if t == "string" then 749 | return self:new_str(v) 750 | elseif t == "boolean" then 751 | return get_pri(v) 752 | elseif t == "number" then 753 | return to_lua_num(v) 754 | elseif allow_nil and v == nil then 755 | return "nil" 756 | end 757 | error("wtfff") 758 | end 759 | 760 | do 761 | local proto_i = 1 762 | 763 | function Parser:loop() 764 | local proto = self.proto 765 | local instructions = proto.instructions 766 | local targets = proto.targets 767 | for pc = 1, #instructions do 768 | local ins = instructions[pc] 769 | local target = targets[pc] 770 | local op = ins.OP 771 | if target then 772 | self:end_scope() 773 | 774 | if self.skip_target then 775 | self.skip_target = nil 776 | else 777 | self:write("::") 778 | self:write(self:get_var(pc)) 779 | self:write("::") 780 | end 781 | 782 | self:start_scope("do ") 783 | end 784 | 785 | OPS[op](self, ins.A, ins.B, ins.C, ins.D, op, pc) 786 | 787 | if conditionals[op] then 788 | end_condition = true 789 | end 790 | 791 | if loops[op] then 792 | OPS["JMP"](self, ins.A, ins.B, ins.C, ins.D, op, pc) 793 | end 794 | 795 | if op ~= "UCLO" then 796 | self.last_op = op 797 | end 798 | end 799 | 800 | for i = 1, self.scope do 801 | self:end_scope() 802 | end 803 | 804 | proto_i = proto_i - 1 805 | 806 | local vars = {} 807 | for k, v in pairs(self.vars) do 808 | if v ~= 0 then 809 | table.insert(vars, math.random(1, #vars + 1), self:get_var(k)) 810 | end 811 | end 812 | 813 | if #vars > 0 then 814 | table.insert(self.output, 1, "local " .. table.concat(vars, ",") .. ";") 815 | end 816 | 817 | return table.concat(self.output):gsub("%s+", " ") 818 | end 819 | 820 | function Parser.new(proto, parent) 821 | proto_i = proto_i + 1 822 | return setmetatable({ 823 | proto = proto, 824 | id = proto_i - 1, 825 | output = {}, 826 | vars = {}, 827 | parent = parent, 828 | scope = 0, 829 | table_values = {}, 830 | used_targets = {}, 831 | add_to_vars = 0, 832 | mangled_vars = {}, 833 | var_names = {} 834 | }, Parser) 835 | end 836 | end 837 | 838 | local open = io.open 839 | local write_file = function(path, content) 840 | local f = open(path, "wb") 841 | if not f then 842 | error(("File '%s' couldn't be created!"):format(path)) 843 | end 844 | f:write(content) 845 | f:close() 846 | end 847 | 848 | local file_exists = function(name) 849 | local f = io.open(name, "r") 850 | if f ~= nil then 851 | io.close(f) 852 | return true 853 | else 854 | return false 855 | end 856 | end 857 | 858 | local inputs = {...} 859 | local input_file = inputs[1] 860 | 861 | if not input_file or not file_exists(input_file) then 862 | error("Invalid file to obfuscate!") 863 | end 864 | 865 | local output_file = inputs[2] 866 | if type(output_file) ~= "string" then 867 | error("output file needs to be a string!") 868 | end 869 | 870 | use_utf8 = inputs[3] == "USE_UTF8" 871 | 872 | os.execute("gluac\\gluac.exe -s " .. input_file) 873 | 874 | local bc = loadfile("bc.lua") 875 | local dis = require("libs/dis_bc") 876 | local proto = dis(bc) 877 | write_file(output_file, Parser.new(proto):loop()) --------------------------------------------------------------------------------