File manager - Edit - /home/newsbmcs.com/public_html/static/img/logo/luajit-2.1.0-beta3.tar
Back
jit/bcsave.lua 0000644 00000043650 15027445263 0007320 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT module to save/list bytecode. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module saves or lists the bytecode for an input file. -- It's run by the -b command line option. -- ------------------------------------------------------------------------------ local jit = require("jit") assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") local bit = require("bit") -- Symbol name prefix for LuaJIT bytecode. local LJBC_PREFIX = "luaJIT_BC_" ------------------------------------------------------------------------------ local function usage() io.stderr:write[[ Save LuaJIT bytecode: luajit -b[options] input output -l Only list bytecode. -s Strip debug info (default). -g Keep debug info. -n name Set module name (default: auto-detect from input name). -t type Set output file type (default: auto-detect from output name). -a arch Override architecture for object files (default: native). -o os Override OS for object files (default: native). -e chunk Use chunk string as input. -- Stop handling options. - Use stdin as input and/or stdout as output. File types: c h obj o raw (default) ]] os.exit(1) end local function check(ok, ...) if ok then return ok, ... end io.stderr:write("luajit: ", ...) io.stderr:write("\n") os.exit(1) end local function readfile(input) if type(input) == "function" then return input end if input == "-" then input = nil end return check(loadfile(input)) end local function savefile(name, mode) if name == "-" then return io.stdout end return check(io.open(name, mode)) end ------------------------------------------------------------------------------ local map_type = { raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", } local map_arch = { x86 = true, x64 = true, arm = true, arm64 = true, arm64be = true, ppc = true, mips = true, mipsel = true, } local map_os = { linux = true, windows = true, osx = true, freebsd = true, netbsd = true, openbsd = true, dragonfly = true, solaris = true, } local function checkarg(str, map, err) str = string.lower(str) local s = check(map[str], "unknown ", err) return s == true and str or s end local function detecttype(str) local ext = string.match(string.lower(str), "%.(%a+)$") return map_type[ext] or "raw" end local function checkmodname(str) check(string.match(str, "^[%w_.%-]+$"), "bad module name") return string.gsub(str, "[%.%-]", "_") end local function detectmodname(str) if type(str) == "string" then local tail = string.match(str, "[^/\\]+$") if tail then str = tail end local head = string.match(str, "^(.*)%.[^.]*$") if head then str = head end str = string.match(str, "^[%w_.%-]+") else str = nil end check(str, "cannot derive module name, use -n name") return string.gsub(str, "[%.%-]", "_") end ------------------------------------------------------------------------------ local function bcsave_tail(fp, output, s) local ok, err = fp:write(s) if ok and output ~= "-" then ok, err = fp:close() end check(ok, "cannot write ", output, ": ", err) end local function bcsave_raw(output, s) local fp = savefile(output, "wb") bcsave_tail(fp, output, s) end local function bcsave_c(ctx, output, s) local fp = savefile(output, "w") if ctx.type == "c" then fp:write(string.format([[ #ifdef _cplusplus extern "C" #endif #ifdef _WIN32 __declspec(dllexport) #endif const unsigned char %s%s[] = { ]], LJBC_PREFIX, ctx.modname)) else fp:write(string.format([[ #define %s%s_SIZE %d static const unsigned char %s%s[] = { ]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) end local t, n, m = {}, 0, 0 for i=1,#s do local b = tostring(string.byte(s, i)) m = m + #b + 1 if m > 78 then fp:write(table.concat(t, ",", 1, n), ",\n") n, m = 0, #b + 1 end n = n + 1 t[n] = b end bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") end local function bcsave_elfobj(ctx, output, s, ffi) ffi.cdef[[ typedef struct { uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; uint16_t type, machine; uint32_t version; uint32_t entry, phofs, shofs; uint32_t flags; uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; } ELF32header; typedef struct { uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; uint16_t type, machine; uint32_t version; uint64_t entry, phofs, shofs; uint32_t flags; uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; } ELF64header; typedef struct { uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; } ELF32sectheader; typedef struct { uint32_t name, type; uint64_t flags, addr, ofs, size; uint32_t link, info; uint64_t align, entsize; } ELF64sectheader; typedef struct { uint32_t name, value, size; uint8_t info, other; uint16_t sectidx; } ELF32symbol; typedef struct { uint32_t name; uint8_t info, other; uint16_t sectidx; uint64_t value, size; } ELF64symbol; typedef struct { ELF32header hdr; ELF32sectheader sect[6]; ELF32symbol sym[2]; uint8_t space[4096]; } ELF32obj; typedef struct { ELF64header hdr; ELF64sectheader sect[6]; ELF64symbol sym[2]; uint8_t space[4096]; } ELF64obj; ]] local symname = LJBC_PREFIX..ctx.modname local is64, isbe = false, false if ctx.arch == "x64" or ctx.arch == "arm64" or ctx.arch == "arm64be" then is64 = true elseif ctx.arch == "ppc" or ctx.arch == "mips" then isbe = true end -- Handle different host/target endianess. local function f32(x) return x end local f16, fofs = f32, f32 if ffi.abi("be") ~= isbe then f32 = bit.bswap function f16(x) return bit.rshift(bit.bswap(x), 16) end if is64 then local two32 = ffi.cast("int64_t", 2^32) function fofs(x) return bit.bswap(x)*two32 end else fofs = f32 end end -- Create ELF object and fill in header. local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") local hdr = o.hdr if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. local bf = assert(io.open("/bin/ls", "rb")) local bs = bf:read(9) bf:close() ffi.copy(o, bs, 9) check(hdr.emagic[0] == 127, "no support for writing native object files") else hdr.emagic = "\127ELF" hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 end hdr.eclass = is64 and 2 or 1 hdr.eendian = isbe and 2 or 1 hdr.eversion = 1 hdr.type = f16(1) hdr.machine = f16(({ x86=3, x64=62, arm=40, arm64=183, arm64be=183, ppc=20, mips=8, mipsel=8 })[ctx.arch]) if ctx.arch == "mips" or ctx.arch == "mipsel" then hdr.flags = f32(0x50001006) end hdr.version = f32(1) hdr.shofs = fofs(ffi.offsetof(o, "sect")) hdr.ehsize = f16(ffi.sizeof(hdr)) hdr.shentsize = f16(ffi.sizeof(o.sect[0])) hdr.shnum = f16(6) hdr.shstridx = f16(2) -- Fill in sections and symbols. local sofs, ofs = ffi.offsetof(o, "space"), 1 for i,name in ipairs{ ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", } do local sect = o.sect[i] sect.align = fofs(1) sect.name = f32(ofs) ffi.copy(o.space+ofs, name) ofs = ofs + #name+1 end o.sect[1].type = f32(2) -- .symtab o.sect[1].link = f32(3) o.sect[1].info = f32(1) o.sect[1].align = fofs(8) o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) o.sect[1].size = fofs(ffi.sizeof(o.sym)) o.sym[1].name = f32(1) o.sym[1].sectidx = f16(4) o.sym[1].size = fofs(#s) o.sym[1].info = 17 o.sect[2].type = f32(3) -- .shstrtab o.sect[2].ofs = fofs(sofs) o.sect[2].size = fofs(ofs) o.sect[3].type = f32(3) -- .strtab o.sect[3].ofs = fofs(sofs + ofs) o.sect[3].size = fofs(#symname+1) ffi.copy(o.space+ofs+1, symname) ofs = ofs + #symname + 2 o.sect[4].type = f32(1) -- .rodata o.sect[4].flags = fofs(2) o.sect[4].ofs = fofs(sofs + ofs) o.sect[4].size = fofs(#s) o.sect[5].type = f32(1) -- .note.GNU-stack o.sect[5].ofs = fofs(sofs + ofs + #s) -- Write ELF object file. local fp = savefile(output, "wb") fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) bcsave_tail(fp, output, s) end local function bcsave_peobj(ctx, output, s, ffi) ffi.cdef[[ typedef struct { uint16_t arch, nsects; uint32_t time, symtabofs, nsyms; uint16_t opthdrsz, flags; } PEheader; typedef struct { char name[8]; uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; uint16_t nreloc, nline; uint32_t flags; } PEsection; typedef struct __attribute((packed)) { union { char name[8]; uint32_t nameref[2]; }; uint32_t value; int16_t sect; uint16_t type; uint8_t scl, naux; } PEsym; typedef struct __attribute((packed)) { uint32_t size; uint16_t nreloc, nline; uint32_t cksum; uint16_t assoc; uint8_t comdatsel, unused[3]; } PEsymaux; typedef struct { PEheader hdr; PEsection sect[2]; // Must be an even number of symbol structs. PEsym sym0; PEsymaux sym0aux; PEsym sym1; PEsymaux sym1aux; PEsym sym2; PEsym sym3; uint32_t strtabsize; uint8_t space[4096]; } PEobj; ]] local symname = LJBC_PREFIX..ctx.modname local is64 = false if ctx.arch == "x86" then symname = "_"..symname elseif ctx.arch == "x64" then is64 = true end local symexport = " /EXPORT:"..symname..",DATA " -- The file format is always little-endian. Swap if the host is big-endian. local function f32(x) return x end local f16 = f32 if ffi.abi("be") then f32 = bit.bswap function f16(x) return bit.rshift(bit.bswap(x), 16) end end -- Create PE object and fill in header. local o = ffi.new("PEobj") local hdr = o.hdr hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) hdr.nsects = f16(2) hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) hdr.nsyms = f32(6) -- Fill in sections and symbols. o.sect[0].name = ".drectve" o.sect[0].size = f32(#symexport) o.sect[0].flags = f32(0x00100a00) o.sym0.sect = f16(1) o.sym0.scl = 3 o.sym0.name = ".drectve" o.sym0.naux = 1 o.sym0aux.size = f32(#symexport) o.sect[1].name = ".rdata" o.sect[1].size = f32(#s) o.sect[1].flags = f32(0x40300040) o.sym1.sect = f16(2) o.sym1.scl = 3 o.sym1.name = ".rdata" o.sym1.naux = 1 o.sym1aux.size = f32(#s) o.sym2.sect = f16(2) o.sym2.scl = 2 o.sym2.nameref[1] = f32(4) o.sym3.sect = f16(-1) o.sym3.scl = 2 o.sym3.value = f32(1) o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. ffi.copy(o.space, symname) local ofs = #symname + 1 o.strtabsize = f32(ofs + 4) o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) ffi.copy(o.space + ofs, symexport) ofs = ofs + #symexport o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) -- Write PE object file. local fp = savefile(output, "wb") fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) bcsave_tail(fp, output, s) end local function bcsave_machobj(ctx, output, s, ffi) ffi.cdef[[ typedef struct { uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; } mach_header; typedef struct { mach_header; uint32_t reserved; } mach_header_64; typedef struct { uint32_t cmd, cmdsize; char segname[16]; uint32_t vmaddr, vmsize, fileoff, filesize; uint32_t maxprot, initprot, nsects, flags; } mach_segment_command; typedef struct { uint32_t cmd, cmdsize; char segname[16]; uint64_t vmaddr, vmsize, fileoff, filesize; uint32_t maxprot, initprot, nsects, flags; } mach_segment_command_64; typedef struct { char sectname[16], segname[16]; uint32_t addr, size; uint32_t offset, align, reloff, nreloc, flags; uint32_t reserved1, reserved2; } mach_section; typedef struct { char sectname[16], segname[16]; uint64_t addr, size; uint32_t offset, align, reloff, nreloc, flags; uint32_t reserved1, reserved2, reserved3; } mach_section_64; typedef struct { uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; } mach_symtab_command; typedef struct { int32_t strx; uint8_t type, sect; int16_t desc; uint32_t value; } mach_nlist; typedef struct { uint32_t strx; uint8_t type, sect; uint16_t desc; uint64_t value; } mach_nlist_64; typedef struct { uint32_t magic, nfat_arch; } mach_fat_header; typedef struct { uint32_t cputype, cpusubtype, offset, size, align; } mach_fat_arch; typedef struct { struct { mach_header hdr; mach_segment_command seg; mach_section sec; mach_symtab_command sym; } arch[1]; mach_nlist sym_entry; uint8_t space[4096]; } mach_obj; typedef struct { struct { mach_header_64 hdr; mach_segment_command_64 seg; mach_section_64 sec; mach_symtab_command sym; } arch[1]; mach_nlist_64 sym_entry; uint8_t space[4096]; } mach_obj_64; typedef struct { mach_fat_header fat; mach_fat_arch fat_arch[2]; struct { mach_header hdr; mach_segment_command seg; mach_section sec; mach_symtab_command sym; } arch[2]; mach_nlist sym_entry; uint8_t space[4096]; } mach_fat_obj; ]] local symname = '_'..LJBC_PREFIX..ctx.modname local isfat, is64, align, mobj = false, false, 4, "mach_obj" if ctx.arch == "x64" then is64, align, mobj = true, 8, "mach_obj_64" elseif ctx.arch == "arm" then isfat, mobj = true, "mach_fat_obj" elseif ctx.arch == "arm64" then is64, align, isfat, mobj = true, 8, true, "mach_fat_obj" else check(ctx.arch == "x86", "unsupported architecture for OSX") end local function aligned(v, a) return bit.band(v+a-1, -a) end local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE. -- Create Mach-O object and fill in header. local o = ffi.new(mobj) local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch] local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch] if isfat then o.fat.magic = be32(0xcafebabe) o.fat.nfat_arch = be32(#cpusubtype) end -- Fill in sections and symbols. for i=0,#cpusubtype-1 do local ofs = 0 if isfat then local a = o.fat_arch[i] a.cputype = be32(cputype[i+1]) a.cpusubtype = be32(cpusubtype[i+1]) -- Subsequent slices overlap each other to share data. ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) a.offset = be32(ofs) a.size = be32(mach_size-ofs+#s) end local a = o.arch[i] a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface a.hdr.cputype = cputype[i+1] a.hdr.cpusubtype = cpusubtype[i+1] a.hdr.filetype = 1 a.hdr.ncmds = 2 a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) a.seg.cmd = is64 and 0x19 or 0x1 a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) a.seg.vmsize = #s a.seg.fileoff = mach_size-ofs a.seg.filesize = #s a.seg.maxprot = 1 a.seg.initprot = 1 a.seg.nsects = 1 ffi.copy(a.sec.sectname, "__data") ffi.copy(a.sec.segname, "__DATA") a.sec.size = #s a.sec.offset = mach_size-ofs a.sym.cmd = 2 a.sym.cmdsize = ffi.sizeof(a.sym) a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs a.sym.nsyms = 1 a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs a.sym.strsize = aligned(#symname+2, align) end o.sym_entry.type = 0xf o.sym_entry.sect = 1 o.sym_entry.strx = 1 ffi.copy(o.space+1, symname) -- Write Macho-O object file. local fp = savefile(output, "wb") fp:write(ffi.string(o, mach_size)) bcsave_tail(fp, output, s) end local function bcsave_obj(ctx, output, s) local ok, ffi = pcall(require, "ffi") check(ok, "FFI library required to write this file type") if ctx.os == "windows" then return bcsave_peobj(ctx, output, s, ffi) elseif ctx.os == "osx" then return bcsave_machobj(ctx, output, s, ffi) else return bcsave_elfobj(ctx, output, s, ffi) end end ------------------------------------------------------------------------------ local function bclist(input, output) local f = readfile(input) require("jit.bc").dump(f, savefile(output, "w"), true) end local function bcsave(ctx, input, output) local f = readfile(input) local s = string.dump(f, ctx.strip) local t = ctx.type if not t then t = detecttype(output) ctx.type = t end if t == "raw" then bcsave_raw(output, s) else if not ctx.modname then ctx.modname = detectmodname(input) end if t == "obj" then bcsave_obj(ctx, output, s) else bcsave_c(ctx, output, s) end end end local function docmd(...) local arg = {...} local n = 1 local list = false local ctx = { strip = true, arch = jit.arch, os = string.lower(jit.os), type = false, modname = false, } while n <= #arg do local a = arg[n] if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then table.remove(arg, n) if a == "--" then break end for m=2,#a do local opt = string.sub(a, m, m) if opt == "l" then list = true elseif opt == "s" then ctx.strip = true elseif opt == "g" then ctx.strip = false else if arg[n] == nil or m ~= #a then usage() end if opt == "e" then if n ~= 1 then usage() end arg[1] = check(loadstring(arg[1])) elseif opt == "n" then ctx.modname = checkmodname(table.remove(arg, n)) elseif opt == "t" then ctx.type = checkarg(table.remove(arg, n), map_type, "file type") elseif opt == "a" then ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") elseif opt == "o" then ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") else usage() end end end else n = n + 1 end end if list then if #arg == 0 or #arg > 2 then usage() end bclist(arg[1], arg[2] or "-") else if #arg ~= 2 then usage() end bcsave(ctx, arg[1], arg[2]) end end ------------------------------------------------------------------------------ -- Public module functions. return { start = docmd -- Process -b command line option. } jit/zone.lua 0000644 00000001752 15027445263 0007025 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT profiler zones. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module implements a simple hierarchical zone model. -- -- Example usage: -- -- local zone = require("jit.zone") -- zone("AI") -- ... -- zone("A*") -- ... -- print(zone:get()) --> "A*" -- ... -- zone() -- ... -- print(zone:get()) --> "AI" -- ... -- zone() -- ---------------------------------------------------------------------------- local remove = table.remove return setmetatable({ flush = function(t) for i=#t,1,-1 do t[i] = nil end end, get = function(t) return t[#t] end }, { __call = function(t, zone) if zone then t[#t+1] = zone else return (assert(remove(t), "empty zone stack")) end end }) jit/dis_x64.lua 0000644 00000001310 15027445263 0007320 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT x64 disassembler wrapper module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This module just exports the 64 bit functions from the combined -- x86/x64 disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------ local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86") return { create = dis_x86.create64, disass = dis_x86.disass64, regname = dis_x86.regname64 } jit/p.lua 0000644 00000021657 15027445263 0006317 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT profiler. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module is a simple command line interface to the built-in -- low-overhead profiler of LuaJIT. -- -- The lower-level API of the profiler is accessible via the "jit.profile" -- module or the luaJIT_profile_* C API. -- -- Example usage: -- -- luajit -jp myapp.lua -- luajit -jp=s myapp.lua -- luajit -jp=-s myapp.lua -- luajit -jp=vl myapp.lua -- luajit -jp=G,profile.txt myapp.lua -- -- The following dump features are available: -- -- f Stack dump: function name, otherwise module:line. Default mode. -- F Stack dump: ditto, but always prepend module. -- l Stack dump: module:line. -- <number> stack dump depth (callee < caller). Default: 1. -- -<number> Inverse stack dump depth (caller > callee). -- s Split stack dump after first stack level. Implies abs(depth) >= 2. -- p Show full path for module names. -- v Show VM states. Can be combined with stack dumps, e.g. vf or fv. -- z Show zones. Can be combined with stack dumps, e.g. zf or fz. -- r Show raw sample counts. Default: show percentages. -- a Annotate excerpts from source code files. -- A Annotate complete source code files. -- G Produce raw output suitable for graphical tools (e.g. flame graphs). -- m<number> Minimum sample percentage to be shown. Default: 3. -- i<number> Sampling interval in milliseconds. Default: 10. -- ---------------------------------------------------------------------------- -- Cache some library functions and objects. local jit = require("jit") assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") local profile = require("jit.profile") local vmdef = require("jit.vmdef") local math = math local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor local sort, format = table.sort, string.format local stdout = io.stdout local zone -- Load jit.zone module on demand. -- Output file handle. local out ------------------------------------------------------------------------------ local prof_ud local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth local prof_ann, prof_count1, prof_count2, prof_samples local map_vmmode = { N = "Compiled", I = "Interpreted", C = "C code", G = "Garbage Collector", J = "JIT Compiler", } -- Profiler callback. local function prof_cb(th, samples, vmmode) prof_samples = prof_samples + samples local key_stack, key_stack2, key_state -- Collect keys for sample. if prof_states then if prof_states == "v" then key_state = map_vmmode[vmmode] or vmmode else key_state = zone:get() or "(none)" end end if prof_fmt then key_stack = profile.dumpstack(th, prof_fmt, prof_depth) key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x) return vmdef.ffnames[tonumber(x)] end) if prof_split == 2 then local k1, k2 = key_stack:match("(.-) [<>] (.*)") if k2 then key_stack, key_stack2 = k1, k2 end elseif prof_split == 3 then key_stack2 = profile.dumpstack(th, "l", 1) end end -- Order keys. local k1, k2 if prof_split == 1 then if key_state then k1 = key_state if key_stack then k2 = key_stack end end elseif key_stack then k1 = key_stack if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end end -- Coalesce samples in one or two levels. if k1 then local t1 = prof_count1 t1[k1] = (t1[k1] or 0) + samples if k2 then local t2 = prof_count2 local t3 = t2[k1] if not t3 then t3 = {}; t2[k1] = t3 end t3[k2] = (t3[k2] or 0) + samples end end end ------------------------------------------------------------------------------ -- Show top N list. local function prof_top(count1, count2, samples, indent) local t, n = {}, 0 for k in pairs(count1) do n = n + 1 t[n] = k end sort(t, function(a, b) return count1[a] > count1[b] end) for i=1,n do local k = t[i] local v = count1[k] local pct = floor(v*100/samples + 0.5) if pct < prof_min then break end if not prof_raw then out:write(format("%s%2d%% %s\n", indent, pct, k)) elseif prof_raw == "r" then out:write(format("%s%5d %s\n", indent, v, k)) else out:write(format("%s %d\n", k, v)) end if count2 then local r = count2[k] if r then prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and " -- " or (prof_depth < 0 and " -> " or " <- ")) end end end end -- Annotate source code local function prof_annotate(count1, samples) local files = {} local ms = 0 for k, v in pairs(count1) do local pct = floor(v*100/samples + 0.5) ms = math.max(ms, v) if pct >= prof_min then local file, line = k:match("^(.*):(%d+)$") if not file then file = k; line = 0 end local fl = files[file] if not fl then fl = {}; files[file] = fl; files[#files+1] = file end line = tonumber(line) fl[line] = prof_raw and v or pct end end sort(files) local fmtv, fmtn = " %3d%% | %s\n", " | %s\n" if prof_raw then local n = math.max(5, math.ceil(math.log10(ms))) fmtv = "%"..n.."d | %s\n" fmtn = (" "):rep(n).." | %s\n" end local ann = prof_ann for _, file in ipairs(files) do local f0 = file:byte() if f0 == 40 or f0 == 91 then out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file)) break end local fp, err = io.open(file) if not fp then out:write(format("====== ERROR: %s: %s\n", file, err)) break end out:write(format("\n====== %s ======\n", file)) local fl = files[file] local n, show = 1, false if ann ~= 0 then for i=1,ann do if fl[i] then show = true; out:write("@@ 1 @@\n"); break end end end for line in fp:lines() do if line:byte() == 27 then out:write("[Cannot annotate bytecode file]\n") break end local v = fl[n] if ann ~= 0 then local v2 = fl[n+ann] if show then if v2 then show = n+ann elseif v then show = n elseif show+ann < n then show = false end elseif v2 then show = n+ann out:write(format("@@ %d @@\n", n)) end if not show then goto next end end if v then out:write(format(fmtv, v, line)) else out:write(format(fmtn, line)) end ::next:: n = n + 1 end fp:close() end end ------------------------------------------------------------------------------ -- Finish profiling and dump result. local function prof_finish() if prof_ud then profile.stop() local samples = prof_samples if samples == 0 then if prof_raw ~= true then out:write("[No samples collected]\n") end return end if prof_ann then prof_annotate(prof_count1, samples) else prof_top(prof_count1, prof_count2, samples, "") end prof_count1 = nil prof_count2 = nil prof_ud = nil end end -- Start profiling. local function prof_start(mode) local interval = "" mode = mode:gsub("i%d*", function(s) interval = s; return "" end) prof_min = 3 mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end) prof_depth = 1 mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end) local m = {} for c in mode:gmatch(".") do m[c] = c end prof_states = m.z or m.v if prof_states == "z" then zone = require("jit.zone") end local scope = m.l or m.f or m.F or (prof_states and "" or "f") local flags = (m.p or "") prof_raw = m.r if m.s then prof_split = 2 if prof_depth == -1 or m["-"] then prof_depth = -2 elseif prof_depth == 1 then prof_depth = 2 end elseif mode:find("[fF].*l") then scope = "l" prof_split = 3 else prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0 end prof_ann = m.A and 0 or (m.a and 3) if prof_ann then scope = "l" prof_fmt = "pl" prof_split = 0 prof_depth = 1 elseif m.G and scope ~= "" then prof_fmt = flags..scope.."Z;" prof_depth = -100 prof_raw = true prof_min = 0 elseif scope == "" then prof_fmt = false else local sc = prof_split == 3 and m.f or m.F or scope prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ") end prof_count1 = {} prof_count2 = {} prof_samples = 0 profile.start(scope:lower()..interval, prof_cb) prof_ud = newproxy(true) getmetatable(prof_ud).__gc = prof_finish end ------------------------------------------------------------------------------ local function start(mode, outfile) if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end if outfile then out = outfile == "-" and stdout or assert(io.open(outfile, "w")) else out = stdout end prof_start(mode or "f") end -- Public module functions. return { start = start, -- For -j command line option. stop = prof_finish } jit/dis_ppc.lua 0000644 00000047515 15027445263 0007502 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT PPC disassembler module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT/X license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- It disassembles all common, non-privileged 32/64 bit PowerPC instructions -- plus the e500 SPE instructions and some Cell/Xenon extensions. -- -- NYI: VMX, VMX128 ------------------------------------------------------------------------------ local type = type local byte, format = string.byte, string.format local match, gmatch, gsub = string.match, string.gmatch, string.gsub local concat = table.concat local bit = require("bit") local band, bor, tohex = bit.band, bit.bor, bit.tohex local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift ------------------------------------------------------------------------------ -- Primary and extended opcode maps ------------------------------------------------------------------------------ local map_crops = { shift = 1, mask = 1023, [0] = "mcrfXX", [33] = "crnor|crnotCCC=", [129] = "crandcCCC", [193] = "crxor|crclrCCC%", [225] = "crnandCCC", [257] = "crandCCC", [289] = "creqv|crsetCCC%", [417] = "crorcCCC", [449] = "cror|crmoveCCC=", [16] = "b_lrKB", [528] = "b_ctrKB", [150] = "isync", } local map_rlwinm = setmetatable({ shift = 0, mask = -1, }, { __index = function(t, x) local rot = band(rshift(x, 11), 31) local mb = band(rshift(x, 6), 31) local me = band(rshift(x, 1), 31) if mb == 0 and me == 31-rot then return "slwiRR~A." elseif me == 31 and mb == 32-rot then return "srwiRR~-A." else return "rlwinmRR~AAA." end end }) local map_rld = { shift = 2, mask = 7, [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", { shift = 1, mask = 1, [0] = "rldclRR~RM.", "rldcrRR~RM.", }, } local map_ext = setmetatable({ shift = 1, mask = 1023, [0] = "cmp_YLRR", [32] = "cmpl_YLRR", [4] = "twARR", [68] = "tdARR", [8] = "subfcRRR.", [40] = "subfRRR.", [104] = "negRR.", [136] = "subfeRRR.", [200] = "subfzeRR.", [232] = "subfmeRR.", [520] = "subfcoRRR.", [552] = "subfoRRR.", [616] = "negoRR.", [648] = "subfeoRRR.", [712] = "subfzeoRR.", [744] = "subfmeoRR.", [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", [457] = "divduRRR.", [489] = "divdRRR.", [745] = "mulldoRRR.", [969] = "divduoRRR.", [1001] = "divdoRRR.", [10] = "addcRRR.", [138] = "addeRRR.", [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", [522] = "addcoRRR.", [650] = "addeoRRR.", [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", [459] = "divwuRRR.", [491] = "divwRRR.", [747] = "mullwoRRR.", [971] = "divwouRRR.", [1003] = "divwoRRR.", [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, [339] = { shift = 11, mask = 1023, [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", }, [467] = { shift = 11, mask = 1023, [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", }, [20] = "lwarxRR0R", [84] = "ldarxRR0R", [21] = "ldxRR0R", [53] = "lduxRRR", [149] = "stdxRR0R", [181] = "stduxRRR", [341] = "lwaxRR0R", [373] = "lwauxRRR", [23] = "lwzxRR0R", [55] = "lwzuxRRR", [87] = "lbzxRR0R", [119] = "lbzuxRRR", [151] = "stwxRR0R", [183] = "stwuxRRR", [215] = "stbxRR0R", [247] = "stbuxRRR", [279] = "lhzxRR0R", [311] = "lhzuxRRR", [343] = "lhaxRR0R", [375] = "lhauxRRR", [407] = "sthxRR0R", [439] = "sthuxRRR", [54] = "dcbst-R0R", [86] = "dcbf-R0R", [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", [246] = "dcbtst-R0R", [278] = "dcbt-R0R", [310] = "eciwxRR0R", [438] = "ecowxRR0R", [470] = "dcbi-RR", [598] = { shift = 21, mask = 3, [0] = "sync", "lwsync", "ptesync", }, [758] = "dcba-RR", [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", [26] = "cntlzwRR~", [58] = "cntlzdRR~", [122] = "popcntbRR~", [154] = "prtywRR~", [186] = "prtydRR~", [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", [284] = "eqvRR~R.", [316] = "xorRR~R.", [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", [508] = "cmpbRR~R", [512] = "mcrxrX", [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", [533] = "lswxRR0R", [597] = "lswiRR0A", [661] = "stswxRR0R", [725] = "stswiRR0A", [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", [535] = "lfsxFR0R", [567] = "lfsuxFRR", [599] = "lfdxFR0R", [631] = "lfduxFRR", [663] = "stfsxFR0R", [695] = "stfsuxFRR", [727] = "stfdxFR0R", [759] = "stfduxFR0R", [855] = "lfiwaxFR0R", [983] = "stfiwxFR0R", [24] = "slwRR~R.", [27] = "sldRR~R.", [536] = "srwRR~R.", [792] = "srawRR~R.", [824] = "srawiRR~A.", [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", [539] = "srdRR~R.", }, { __index = function(t, x) if band(x, 31) == 15 then return "iselRRRC" end end }) local map_ld = { shift = 0, mask = 3, [0] = "ldRRE", "lduRRE", "lwaRRE", } local map_std = { shift = 0, mask = 3, [0] = "stdRRE", "stduRRE", } local map_fps = { shift = 5, mask = 1, { shift = 1, mask = 15, [0] = false, false, "fdivsFFF.", false, "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", } } local map_fpd = { shift = 5, mask = 1, [0] = { shift = 1, mask = 1023, [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", [136] = "fnabsF-F.", [264] = "fabsF-F.", [12] = "frspF-F.", [14] = "fctiwF-F.", [15] = "fctiwzF-F.", [583] = "mffsF.", [711] = "mtfsfZF.", [392] = "frinF-F.", [424] = "frizF-F.", [456] = "fripF-F.", [488] = "frimF-F.", [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", }, { shift = 1, mask = 15, [0] = false, false, "fdivFFF.", false, "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", } } local map_spe = { shift = 0, mask = 2047, [512] = "evaddwRRR", [514] = "evaddiwRAR~", [516] = "evsubwRRR~", [518] = "evsubiwRAR~", [520] = "evabsRR", [521] = "evnegRR", [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", [525] = "evcntlzwRR", [526] = "evcntlswRR", [527] = "brincRRR", [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", [544] = "evsrwuRRR", [545] = "evsrwsRRR", [546] = "evsrwiuRRA", [547] = "evsrwisRRA", [548] = "evslwRRR", [550] = "evslwiRRA", [552] = "evrlwRRR", [553] = "evsplatiRS", [554] = "evrlwiRRA", [555] = "evsplatfiRS", [556] = "evmergehiRRR", [557] = "evmergeloRRR", [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", [564] = "evcmpeqYRR", [632] = "evselRRR", [633] = "evselRRRW", [634] = "evselRRRW", [635] = "evselRRRW", [636] = "evselRRRW", [637] = "evselRRRW", [638] = "evselRRRW", [639] = "evselRRRW", [640] = "evfsaddRRR", [641] = "evfssubRRR", [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", [648] = "evfsmulRRR", [649] = "evfsdivRRR", [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", [658] = "evfscfufR-R", [659] = "evfscfsfR-R", [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", [662] = "evfsctufR-R", [663] = "evfsctsfR-R", [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", [704] = "efsaddRRR", [705] = "efssubRRR", [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", [712] = "efsmulRRR", [713] = "efsdivRRR", [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", [719] = "efscfdR-R", [720] = "efscfuiR-R", [721] = "efscfsiR-R", [722] = "efscfufR-R", [723] = "efscfsfR-R", [724] = "efsctuiR-R", [725] = "efsctsiR-R", [726] = "efsctufR-R", [727] = "efsctsfR-R", [728] = "efsctuizR-R", [730] = "efsctsizR-R", [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", [736] = "efdaddRRR", [737] = "efdsubRRR", [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", [744] = "efdmulRRR", [745] = "efddivRRR", [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", [751] = "efdcfsR-R", [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", [754] = "efdcfufR-R", [755] = "efdcfsfR-R", [756] = "efdctuiR-R", [757] = "efdctsiR-R", [758] = "efdctufR-R", [759] = "efdctsfR-R", [760] = "efdctuizR-R", [762] = "efdctsizR-R", [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", [768] = "evlddxRR0R", [769] = "evlddRR8", [770] = "evldwxRR0R", [771] = "evldwRR8", [772] = "evldhxRR0R", [773] = "evldhRR8", [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", [784] = "evlwhexRR0R", [785] = "evlwheRR4", [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", [800] = "evstddxRR0R", [801] = "evstddRR8", [802] = "evstdwxRR0R", [803] = "evstdwRR8", [804] = "evstdhxRR0R", [805] = "evstdhRR8", [816] = "evstwhexRR0R", [817] = "evstwheRR4", [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", [824] = "evstwwexRR0R", [825] = "evstwweRR4", [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", [1147] = "evmwsmfaRRR", [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", [1220] = "evmraRR", [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", } local map_pri = { [0] = false, false, "tdiARI", "twiARI", map_spe, false, false, "mulliRRI", "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", "b_KBJ", "sc", "bKJ", map_crops, "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", "andi.RR~U", "andis.RR~U", map_rld, map_ext, "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", false, false, map_ld, map_fps, false, false, map_std, map_fpd, } ------------------------------------------------------------------------------ local map_gpr = { [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", } local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } -- Format a condition bit. local function condfmt(cond) if cond <= 3 then return map_cond[band(cond, 3)] else return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) end end ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local pos = ctx.pos local extra = "" if ctx.rel then local sym = ctx.symtab[ctx.rel] if sym then extra = "\t->"..sym end end if ctx.hexdump > 0 then ctx.out(format("%08x %s %-7s %s%s\n", ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) else ctx.out(format("%08x %-7s %s%s\n", ctx.addr+pos, text, concat(operands, ", "), extra)) end ctx.pos = pos + 4 end -- Fallback for unknown opcodes. local function unknown(ctx) return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) end -- Disassemble a single instruction. local function disass_ins(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) local operands = {} local last = nil local rs = 21 ctx.op = op ctx.rel = nil local opat = map_pri[rshift(b0, 2)] while type(opat) ~= "string" do if not opat then return unknown(ctx) end opat = opat[band(rshift(op, opat.shift), opat.mask)] end local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") if altname then pat = pat2 end for p in gmatch(pat, ".") do local x = nil if p == "R" then x = map_gpr[band(rshift(op, rs), 31)] rs = rs - 5 elseif p == "F" then x = "f"..band(rshift(op, rs), 31) rs = rs - 5 elseif p == "A" then x = band(rshift(op, rs), 31) rs = rs - 5 elseif p == "S" then x = arshift(lshift(op, 27-rs), 27) rs = rs - 5 elseif p == "I" then x = arshift(lshift(op, 16), 16) elseif p == "U" then x = band(op, 0xffff) elseif p == "D" or p == "E" then local disp = arshift(lshift(op, 16), 16) if p == "E" then disp = band(disp, -4) end if last == "r0" then last = "0" end operands[#operands] = format("%d(%s)", disp, last) elseif p >= "2" and p <= "8" then local disp = band(rshift(op, rs), 31) * p if last == "r0" then last = "0" end operands[#operands] = format("%d(%s)", disp, last) elseif p == "H" then x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) rs = rs - 5 elseif p == "M" then x = band(rshift(op, rs), 31) + band(op, 0x20) elseif p == "C" then x = condfmt(band(rshift(op, rs), 31)) rs = rs - 5 elseif p == "B" then local bo = rshift(op, 21) local cond = band(rshift(op, 16), 31) local cn = "" rs = rs - 10 if band(bo, 4) == 0 then cn = band(bo, 2) == 0 and "dnz" or "dz" if band(bo, 0x10) == 0 then cn = cn..(band(bo, 8) == 0 and "f" or "t") end if band(bo, 0x10) == 0 then x = condfmt(cond) end name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") elseif band(bo, 0x10) == 0 then cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] if cond > 3 then x = "cr"..rshift(cond, 2) end name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") end name = gsub(name, "_", cn) elseif p == "J" then x = arshift(lshift(op, 27-rs), 29-rs)*4 if band(op, 2) == 0 then x = ctx.addr + pos + x end ctx.rel = x x = "0x"..tohex(x) elseif p == "K" then if band(op, 1) ~= 0 then name = name.."l" end if band(op, 2) ~= 0 then name = name.."a" end elseif p == "X" or p == "Y" then x = band(rshift(op, rs+2), 7) if x == 0 and p == "Y" then x = nil else x = "cr"..x end rs = rs - 5 elseif p == "W" then x = "cr"..band(op, 7) elseif p == "Z" then x = band(rshift(op, rs-4), 255) rs = rs - 10 elseif p == ">" then operands[#operands] = rshift(operands[#operands], 1) elseif p == "0" then if last == "r0" then operands[#operands] = nil if altname then name = altname end end elseif p == "L" then name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") elseif p == "." then if band(op, 1) == 1 then name = name.."." end elseif p == "N" then if op == 0x60000000 then name = "nop"; break end elseif p == "~" then local n = #operands operands[n-1], operands[n] = operands[n], operands[n-1] elseif p == "=" then local n = #operands if last == operands[n-1] then operands[n] = nil name = altname end elseif p == "%" then local n = #operands if last == operands[n-1] and last == operands[n-2] then operands[n] = nil operands[n-1] = nil name = altname end elseif p == "-" then rs = rs - 5 else assert(false) end if x then operands[#operands+1] = x; last = x end end return putop(ctx, name, operands) end ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code stop = stop - stop % 4 ctx.pos = ofs - ofs % 4 ctx.rel = nil while ctx.pos < stop do disass_ins(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = addr or 0 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 8 return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 32 then return map_gpr[r] end return "f"..(r-32) end -- Public module functions. return { create = create, disass = disass, regname = regname } jit/dis_mips64el.lua 0000644 00000001315 15027445263 0010347 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT MIPS64EL disassembler wrapper module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This module just exports the little-endian functions from the -- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------ local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") return { create = dis_mips.create_el, disass = dis_mips.disass_el, regname = dis_mips.regname } jit/vmdef.lua 0000644 00000016345 15027445263 0007157 0 ustar 00 -- This is a generated file. DO NOT EDIT! return { bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF ISTYPEISNUM 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 TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW", irnames = "LT GE LE GT ULT UGE ULE UGT EQ NE ABC RETF NOP BASE PVAL GCSTEPHIOP LOOP USE PHI RENAMEPROF KPRI 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 STRREFLREF ALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ASTOREHSTOREUSTOREFSTOREXSTORESNEW XSNEW TNEW TDUP CNEW CNEWI BUFHDRBUFPUTBUFSTRTBAR OBAR XBAR CONV TOBIT TOSTR STRTO CALLN CALLA CALLL CALLS CALLXSCARG ", irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "exp", "exp2", "log", "log2", "log10", "sin", "cos", "tan", "other", }, irfield = { [0]="str.len", "func.env", "func.pc", "func.ffid", "thread.env", "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", }, ircall = { [0]="lj_str_cmp", "lj_str_find", "lj_str_new", "lj_strscan_num", "lj_strfmt_int", "lj_strfmt_num", "lj_strfmt_char", "lj_strfmt_putint", "lj_strfmt_putnum", "lj_strfmt_putquoted", "lj_strfmt_putfxint", "lj_strfmt_putfnum_int", "lj_strfmt_putfnum_uint", "lj_strfmt_putfnum", "lj_strfmt_putfstr", "lj_strfmt_putfchar", "lj_buf_putmem", "lj_buf_putstr", "lj_buf_putchar", "lj_buf_putstr_reverse", "lj_buf_putstr_lower", "lj_buf_putstr_upper", "lj_buf_putstr_rep", "lj_buf_puttab", "lj_buf_tostr", "lj_tab_new_ah", "lj_tab_new1", "lj_tab_dup", "lj_tab_clear", "lj_tab_newkey", "lj_tab_len", "lj_gc_step_jit", "lj_gc_barrieruv", "lj_mem_newgco", "lj_math_random_step", "lj_vm_modi", "sinh", "cosh", "tanh", "fputc", "fwrite", "fflush", "lj_vm_floor", "lj_vm_ceil", "lj_vm_trunc", "sqrt", "exp", "lj_vm_exp2", "log", "lj_vm_log2", "log10", "sin", "cos", "tan", "lj_vm_powi", "pow", "atan2", "ldexp", "lj_vm_tobit", "softfp_add", "softfp_sub", "softfp_mul", "softfp_div", "softfp_cmp", "softfp_i2d", "softfp_d2i", "lj_vm_sfmin", "lj_vm_sfmax", "lj_vm_tointg", "softfp_ui2d", "softfp_f2d", "softfp_d2ui", "softfp_d2f", "softfp_i2f", "softfp_ui2f", "softfp_f2i", "softfp_f2ui", "fp64_l2d", "fp64_ul2d", "fp64_l2f", "fp64_ul2f", "fp64_d2l", "fp64_d2ul", "fp64_f2l", "fp64_f2ul", "lj_carith_divi64", "lj_carith_divu64", "lj_carith_modi64", "lj_carith_modu64", "lj_carith_powi64", "lj_carith_powu64", "lj_cdata_newv", "lj_cdata_setfin", "strlen", "memcpy", "memset", "lj_vm_errno", "lj_carith_mul64", "lj_carith_shl64", "lj_carith_shr64", "lj_carith_sar64", "lj_carith_rol64", "lj_carith_ror64", }, traceerr = { [0]="error thrown or hook called during recording", "trace too short", "trace too long", "trace too deep", "too many snapshots", "blacklisted", "retry recording", "NYI: bytecode %d", "leaving loop in root trace", "inner loop in root trace", "loop unroll limit reached", "bad argument type", "JIT compilation disabled for function", "call unroll limit reached", "down-recursion, restarting", "NYI: unsupported variant of FastFunc %s", "NYI: return to lower frame", "store with nil or NaN key", "missing metamethod", "looping index lookup", "NYI: mixed sparse/dense table", "symbol not in cache", "NYI: unsupported C type conversion", "NYI: unsupported C function type", "guard would always fail", "too many PHIs", "persistent type instability", "failed to allocate mcode memory", "machine code too long", "hit mcode limit (retrying)", "too many spill slots", "inconsistent register allocation", "NYI: cannot assemble IR instruction %d", "NYI: PHI shuffling too complex", "NYI: register coalescing too complex", }, ffnames = { [0]="Lua", "C", "assert", "type", "next", "pairs", "ipairs_aux", "ipairs", "getmetatable", "setmetatable", "getfenv", "setfenv", "rawget", "rawset", "rawequal", "unpack", "select", "tonumber", "tostring", "error", "pcall", "xpcall", "loadfile", "load", "loadstring", "dofile", "gcinfo", "collectgarbage", "newproxy", "print", "coroutine.status", "coroutine.running", "coroutine.isyieldable", "coroutine.create", "coroutine.yield", "coroutine.resume", "coroutine.wrap_aux", "coroutine.wrap", "math.abs", "math.floor", "math.ceil", "math.sqrt", "math.log10", "math.exp", "math.sin", "math.cos", "math.tan", "math.asin", "math.acos", "math.atan", "math.sinh", "math.cosh", "math.tanh", "math.frexp", "math.modf", "math.log", "math.atan2", "math.pow", "math.fmod", "math.ldexp", "math.min", "math.max", "math.random", "math.randomseed", "bit.tobit", "bit.bnot", "bit.bswap", "bit.lshift", "bit.rshift", "bit.arshift", "bit.rol", "bit.ror", "bit.band", "bit.bor", "bit.bxor", "bit.tohex", "string.byte", "string.char", "string.sub", "string.rep", "string.reverse", "string.lower", "string.upper", "string.dump", "string.find", "string.match", "string.gmatch_aux", "string.gmatch", "string.gsub", "string.format", "table.maxn", "table.insert", "table.concat", "table.sort", "table.new", "table.clear", "io.method.close", "io.method.read", "io.method.write", "io.method.flush", "io.method.seek", "io.method.setvbuf", "io.method.lines", "io.method.__gc", "io.method.__tostring", "io.open", "io.popen", "io.tmpfile", "io.close", "io.read", "io.write", "io.flush", "io.input", "io.output", "io.lines", "io.type", "os.execute", "os.remove", "os.rename", "os.tmpname", "os.getenv", "os.exit", "os.clock", "os.date", "os.time", "os.difftime", "os.setlocale", "debug.getregistry", "debug.getmetatable", "debug.setmetatable", "debug.getfenv", "debug.setfenv", "debug.getinfo", "debug.getlocal", "debug.setlocal", "debug.getupvalue", "debug.setupvalue", "debug.upvalueid", "debug.upvaluejoin", "debug.sethook", "debug.gethook", "debug.debug", "debug.traceback", "jit.on", "jit.off", "jit.flush", "jit.status", "jit.attach", "jit.util.funcinfo", "jit.util.funcbc", "jit.util.funck", "jit.util.funcuvname", "jit.util.traceinfo", "jit.util.traceir", "jit.util.tracek", "jit.util.tracesnap", "jit.util.tracemc", "jit.util.traceexitstub", "jit.util.ircalladdr", "jit.opt.start", "jit.profile.start", "jit.profile.stop", "jit.profile.dumpstack", "ffi.meta.__index", "ffi.meta.__newindex", "ffi.meta.__eq", "ffi.meta.__len", "ffi.meta.__lt", "ffi.meta.__le", "ffi.meta.__concat", "ffi.meta.__call", "ffi.meta.__add", "ffi.meta.__sub", "ffi.meta.__mul", "ffi.meta.__div", "ffi.meta.__mod", "ffi.meta.__pow", "ffi.meta.__unm", "ffi.meta.__tostring", "ffi.meta.__pairs", "ffi.meta.__ipairs", "ffi.clib.__index", "ffi.clib.__newindex", "ffi.clib.__gc", "ffi.callback.free", "ffi.callback.set", "ffi.cdef", "ffi.new", "ffi.cast", "ffi.typeof", "ffi.typeinfo", "ffi.istype", "ffi.sizeof", "ffi.alignof", "ffi.offsetof", "ffi.errno", "ffi.string", "ffi.copy", "ffi.fill", "ffi.abi", "ffi.metatype", "ffi.gc", "ffi.load", }, } jit/v.lua 0000644 00000013227 15027445263 0006317 0 ustar 00 ---------------------------------------------------------------------------- -- Verbose mode of the LuaJIT compiler. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module shows verbose information about the progress of the -- JIT compiler. It prints one line for each generated trace. This module -- is useful to see which code has been compiled or where the compiler -- punts and falls back to the interpreter. -- -- Example usage: -- -- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end" -- luajit -jv=myapp.out myapp.lua -- -- Default output is to stderr. To redirect the output to a file, pass a -- filename as an argument (use '-' for stdout) or set the environment -- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the -- module is started. -- -- The output from the first example should look like this: -- -- [TRACE 1 (command line):1 loop] -- [TRACE 2 (1/3) (command line):1 -> 1] -- -- The first number in each line is the internal trace number. Next are -- the file name ('(command line)') and the line number (':1') where the -- trace has started. Side traces also show the parent trace number and -- the exit number where they are attached to in parentheses ('(1/3)'). -- An arrow at the end shows where the trace links to ('-> 1'), unless -- it loops to itself. -- -- In this case the inner loop gets hot and is traced first, generating -- a root trace. Then the last exit from the 1st trace gets hot, too, -- and triggers generation of the 2nd trace. The side trace follows the -- path along the outer loop and *around* the inner loop, back to its -- start, and then links to the 1st trace. Yes, this may seem unusual, -- if you know how traditional compilers work. Trace compilers are full -- of surprises like this -- have fun! :-) -- -- Aborted traces are shown like this: -- -- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50] -- -- Don't worry -- trace aborts are quite common, even in programs which -- can be fully compiled. The compiler may retry several times until it -- finds a suitable trace. -- -- Of course this doesn't work with features that are not-yet-implemented -- (NYI error messages). The VM simply falls back to the interpreter. This -- may not matter at all if the particular trace is not very high up in -- the CPU usage profile. Oh, and the interpreter is quite fast, too. -- -- Also check out the -jdump module, which prints all the gory details. -- ------------------------------------------------------------------------------ -- Cache some library functions and objects. local jit = require("jit") assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") local jutil = require("jit.util") local vmdef = require("jit.vmdef") local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo local type, format = type, string.format local stdout, stderr = io.stdout, io.stderr -- Active flag and output file handle. local active, out ------------------------------------------------------------------------------ local startloc, startex local function fmtfunc(func, pc) local fi = funcinfo(func, pc) if fi.loc then return fi.loc elseif fi.ffid then return vmdef.ffnames[fi.ffid] elseif fi.addr then return format("C:%x", fi.addr) else return "(?)" end end -- Format trace error message. local function fmterr(err, info) if type(err) == "number" then if type(info) == "function" then info = fmtfunc(info) end err = format(vmdef.traceerr[err], info) end return err end -- Dump trace states. local function dump_trace(what, tr, func, pc, otr, oex) if what == "start" then startloc = fmtfunc(func, pc) startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or "" else if what == "abort" then local loc = fmtfunc(func, pc) if loc ~= startloc then out:write(format("[TRACE --- %s%s -- %s at %s]\n", startex, startloc, fmterr(otr, oex), loc)) else out:write(format("[TRACE --- %s%s -- %s]\n", startex, startloc, fmterr(otr, oex))) end elseif what == "stop" then local info = traceinfo(tr) local link, ltype = info.link, info.linktype if ltype == "interpreter" then out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", tr, startex, startloc)) elseif ltype == "stitch" then out:write(format("[TRACE %3s %s%s %s %s]\n", tr, startex, startloc, ltype, fmtfunc(func, pc))) elseif link == tr or link == 0 then out:write(format("[TRACE %3s %s%s %s]\n", tr, startex, startloc, ltype)) elseif ltype == "root" then out:write(format("[TRACE %3s %s%s -> %d]\n", tr, startex, startloc, link)) else out:write(format("[TRACE %3s %s%s -> %d %s]\n", tr, startex, startloc, link, ltype)) end else out:write(format("[TRACE %s]\n", what)) end out:flush() end end ------------------------------------------------------------------------------ -- Detach dump handlers. local function dumpoff() if active then active = false jit.attach(dump_trace) if out and out ~= stdout and out ~= stderr then out:close() end out = nil end end -- Open the output file and attach dump handlers. local function dumpon(outfile) if active then dumpoff() end if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end if outfile then out = outfile == "-" and stdout or assert(io.open(outfile, "w")) else out = stderr end jit.attach(dump_trace, "trace") active = true end -- Public module functions. return { on = dumpon, off = dumpoff, start = dumpon -- For -j command line option. } jit/dis_x86.lua 0000644 00000100062 15027445263 0007330 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT x86/x64 disassembler module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- Sending small code snippets to an external disassembler and mixing the -- output with our own stuff was too fragile. So I had to bite the bullet -- and write yet another x86 disassembler. Oh well ... -- -- The output format is very similar to what ndisasm generates. But it has -- been developed independently by looking at the opcode tables from the -- Intel and AMD manuals. The supported instruction set is quite extensive -- and reflects what a current generation Intel or AMD CPU implements in -- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3, -- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor -- (VMX/SVM) instructions. -- -- Notes: -- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported. -- * No attempt at optimization has been made -- it's fast enough for my needs. ------------------------------------------------------------------------------ local type = type local sub, byte, format = string.sub, string.byte, string.format local match, gmatch, gsub = string.match, string.gmatch, string.gsub local lower, rep = string.lower, string.rep local bit = require("bit") local tohex = bit.tohex -- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on. local map_opc1_32 = { --0x [0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es", "orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*", --1x "adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss", "sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds", --2x "andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa", "subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das", --3x "xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa", "cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas", --4x "incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR", "decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR", --5x "pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR", "popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR", --6x "sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr", "fs:seg","gs:seg","o16:","a16", "pushUi","imulVrmi","pushBs","imulVrms", "insb","insVS","outsb","outsVS", --7x "joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj", "jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj", --8x "arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms", "testBmr","testVmr","xchgBrm","xchgVrm", "movBmr","movVmr","movBrm","movVrm", "movVmg","leaVrm","movWgm","popUm", --9x "nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR", "xchgVaR","xchgVaR","xchgVaR","xchgVaR", "sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait", "sz*pushfw,pushf","sz*popfw,popf","sahf","lahf", --Ax "movBao","movVao","movBoa","movVoa", "movsb","movsVS","cmpsb","cmpsVS", "testBai","testVai","stosb","stosVS", "lodsb","lodsVS","scasb","scasVS", --Bx "movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi", "movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI", --Cx "shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi", "enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS", --Dx "shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb", "fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7", --Ex "loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj", "inBau","inVau","outBua","outVua", "callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda", --Fx "lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm", "clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm", } assert(#map_opc1_32 == 255) -- Map for 1st opcode byte in 64 bit mode (overrides only). local map_opc1_64 = setmetatable({ [0x06]=false, [0x07]=false, [0x0e]=false, [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false, [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false, [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:", [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb", [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb", [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb", [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb", [0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false, [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false, }, { __index = map_opc1_32 }) -- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you. -- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2 local map_opc2 = { --0x [0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret", "invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu", --1x "movupsXrm|movssXrvm|movupdXrm|movsdXrvm", "movupsXmr|movssXmvr|movupdXmr|movsdXmvr", "movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", "movlpsXmr||movlpdXmr", "unpcklpsXrvm||unpcklpdXrvm", "unpckhpsXrvm||unpckhpdXrvm", "movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm", "movhpsXmr||movhpdXmr", "$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm", "hintnopVm","hintnopVm","hintnopVm","hintnopVm", --2x "movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil, "movapsXrm||movapdXrm", "movapsXmr||movapdXmr", "cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt", "movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr", "cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm", "cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm", "ucomissXrm||ucomisdXrm", "comissXrm||comisdXrm", --3x "wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec", "opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil, --4x "cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm", "cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm", "cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm", "cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm", --5x "movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm", "rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm", "andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm", "orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm", "addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm", "cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm", "cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm", "subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm", "divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm", --6x "punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm", "pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm", "punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm", "||punpcklqdqXrvm","||punpckhqdqXrvm", "movPrVSm","movqMrm|movdquXrm|movdqaXrm", --7x "pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu", "pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu", "pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|", "vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$", nil,nil, "||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm", "movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr", --8x "joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj", "jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj", --9x "setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm", "setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm", --Ax "push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil, "push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm", --Bx "cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr", "$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt", "|popcntVrm","ud2Dp","bt!Vmu","btcVmr", "bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt", --Cx "xaddBmr","xaddVmr", "cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|", "pinsrwPrvWmu","pextrwDrPmu", "shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp", "bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR", --Dx "||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm", "paddqPrvm","pmullwPrvm", "|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm", "psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm", "paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm", --Ex "pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm", "pmulhuwPrvm","pmulhwPrvm", "|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr", "psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm", "paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm", --Fx "|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm", "pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$", "psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm", "paddbPrvm","paddwPrvm","padddPrvm","ud", } assert(map_opc2[255] == "ud") -- Map for three-byte opcodes. Can't wait for their next invention. local map_opc3 = { ["38"] = { -- [66] 0f 38 xx --0x [0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm", "pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm", "psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm", "||permilpsXrvm","||permilpdXrvm",nil,nil, --1x "||pblendvbXrma",nil,nil,nil, "||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm", "||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil, "pabsbPrm","pabswPrm","pabsdPrm",nil, --2x "||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm", "||pmovsxwqXrm","||pmovsxdqXrm",nil,nil, "||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm", "||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr", --3x "||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm", "||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm", "||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm", "||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm", --4x "||pmulddXrvm","||phminposuwXrm",nil,nil, nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm", --5x [0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm", [0x5a] = "||broadcasti128XrlXm", --7x [0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm", --8x [0x8c] = "||pmaskmovXrvVSm", [0x8e] = "||pmaskmovVSmXvr", --Dx [0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm", [0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm", --Fx [0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt", [0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv", }, ["3a"] = { -- [66] 0f 3a xx --0x [0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil, "||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil, "||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu", "||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu", --1x nil,nil,nil,nil, "||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", "||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil, nil,nil,nil,nil, --2x "||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil, --3x [0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru", --4x [0x40] = "||dppsXrvmu", [0x41] = "||dppdXrvmu", [0x42] = "||mpsadbwXrvmu", [0x44] = "||pclmulqdqXrvmu", [0x46] = "||perm2i128Xrvmu", [0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb", [0x4c] = "||pblendvbXrvmb", --6x [0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu", [0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu", [0xdf] = "||aeskeygenassistXrmu", --Fx [0xf0] = "||| rorxVrmu", }, } -- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands). local map_opcvm = { [0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff", [0xc8]="monitor",[0xc9]="mwait", [0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave", [0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga", [0xf8]="swapgs",[0xf9]="rdtscp", } -- Map for FP opcodes. And you thought stack machines are simple? local map_opcfp = { -- D8-DF 00-BF: opcodes with a memory operand. -- D8 [0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm", "fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm", -- DA "fiaddDm","fimulDm","ficomDm","ficompDm", "fisubDm","fisubrDm","fidivDm","fidivrDm", -- DB "fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp", -- DC "faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm", -- DD "fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm", -- DE "fiaddWm","fimulWm","ficomWm","ficompWm", "fisubWm","fisubrWm","fidivWm","fidivrWm", -- DF "fildWm","fisttpWm","fistWm","fistpWm", "fbld twordFmp","fildQm","fbstp twordFmp","fistpQm", -- xx C0-FF: opcodes with a pseudo-register operand. -- D8 "faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf", -- D9 "fldFf","fxchFf",{"fnop"},nil, {"fchs","fabs",nil,nil,"ftst","fxam"}, {"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"}, {"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"}, {"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"}, -- DA "fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil, -- DB "fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf", {nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil, -- DC "fadd toFf","fmul toFf",nil,nil, "fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf", -- DD "ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil, -- DE "faddpFf","fmulpFf",nil,{nil,"fcompp"}, "fsubrpFf","fsubpFf","fdivrpFf","fdivpFf", -- DF nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil, } assert(map_opcfp[126] == "fcomipFf") -- Map for opcode groups. The subkey is sp from the ModRM byte. local map_opcgroup = { arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" }, testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" }, testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" }, incb = { "inc", "dec" }, incd = { "inc", "dec", "callUmp", "$call farDmp", "jmpUmp", "$jmp farDmp", "pushUm" }, sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" }, sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt", "smsw", nil, "lmsw", "vm*$invlpg" }, bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" }, cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil, nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" }, pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" }, pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" }, pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" }, pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" }, fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr", nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" }, prefetch = { "prefetch", "prefetchw" }, prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" }, } ------------------------------------------------------------------------------ -- Maps for register names. local map_regs = { B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }, D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }, Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }, M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext! X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" }, Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" }, } local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } -- Maps for size names. local map_sz2n = { B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32, } local map_sz2prefix = { B = "byte", W = "word", D = "dword", Q = "qword", M = "qword", X = "xword", Y = "yword", F = "dword", G = "qword", -- No need for sizes/register names for these two. } ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local code, pos, hex = ctx.code, ctx.pos, "" local hmax = ctx.hexdump if hmax > 0 then for i=ctx.start,pos-1 do hex = hex..format("%02X", byte(code, i, i)) end if #hex > hmax then hex = sub(hex, 1, hmax)..". " else hex = hex..rep(" ", hmax-#hex+2) end end if operands then text = text.." "..operands end if ctx.o16 then text = "o16 "..text; ctx.o16 = false end if ctx.a32 then text = "a32 "..text; ctx.a32 = false end if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end if ctx.rex then local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "").. (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "").. (ctx.vexl and "l" or "") if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "") elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false ctx.rex = false; ctx.vexl = false; ctx.vexv = false end if ctx.seg then local text2, n = gsub(text, "%[", "["..ctx.seg..":") if n == 0 then text = ctx.seg.." "..text else text = text2 end ctx.seg = false end if ctx.lock then text = "lock "..text; ctx.lock = false end local imm = ctx.imm if imm then local sym = ctx.symtab[imm] if sym then text = text.."\t->"..sym end end ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text)) ctx.mrm = false ctx.vexv = false ctx.start = pos ctx.imm = nil end -- Clear all prefix flags. local function clearprefixes(ctx) ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false ctx.rex = false; ctx.a32 = false; ctx.vexl = false end -- Fallback for incomplete opcodes at the end. local function incomplete(ctx) ctx.pos = ctx.stop+1 clearprefixes(ctx) return putop(ctx, "(incomplete)") end -- Fallback for unknown opcodes. local function unknown(ctx) clearprefixes(ctx) return putop(ctx, "(unknown)") end -- Return an immediate of the specified size. local function getimm(ctx, pos, n) if pos+n-1 > ctx.stop then return incomplete(ctx) end local code = ctx.code if n == 1 then local b1 = byte(code, pos, pos) return b1 elseif n == 2 then local b1, b2 = byte(code, pos, pos+1) return b1+b2*256 else local b1, b2, b3, b4 = byte(code, pos, pos+3) local imm = b1+b2*256+b3*65536+b4*16777216 ctx.imm = imm return imm end end -- Process pattern string and generate the operands. local function putpat(ctx, name, pat) local operands, regs, sz, mode, sp, rm, sc, rx, sdisp local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl -- Chars used: 1DFGIMPQRSTUVWXYabcdfgijlmoprstuvwxyz for p in gmatch(pat, ".") do local x = nil if p == "V" or p == "U" then if ctx.rexw then sz = "Q"; ctx.rexw = false elseif ctx.o16 then sz = "W"; ctx.o16 = false elseif p == "U" and ctx.x64 then sz = "Q" else sz = "D" end regs = map_regs[sz] elseif p == "T" then if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end regs = map_regs[sz] elseif p == "B" then sz = "B" regs = ctx.rex and map_regs.B64 or map_regs.B elseif match(p, "[WDQMXYFG]") then sz = p if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end regs = map_regs[sz] elseif p == "P" then sz = ctx.o16 and "X" or "M"; ctx.o16 = false if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end regs = map_regs[sz] elseif p == "S" then name = name..lower(sz) elseif p == "s" then local imm = getimm(ctx, pos, 1); if not imm then return end x = imm <= 127 and format("+0x%02x", imm) or format("-0x%02x", 256-imm) pos = pos+1 elseif p == "u" then local imm = getimm(ctx, pos, 1); if not imm then return end x = format("0x%02x", imm) pos = pos+1 elseif p == "b" then local imm = getimm(ctx, pos, 1); if not imm then return end x = regs[imm/16+1] pos = pos+1 elseif p == "w" then local imm = getimm(ctx, pos, 2); if not imm then return end x = format("0x%x", imm) pos = pos+2 elseif p == "o" then -- [offset] if ctx.x64 then local imm1 = getimm(ctx, pos, 4); if not imm1 then return end local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end x = format("[0x%08x%08x]", imm2, imm1) pos = pos+8 else local imm = getimm(ctx, pos, 4); if not imm then return end x = format("[0x%08x]", imm) pos = pos+4 end elseif p == "i" or p == "I" then local n = map_sz2n[sz] if n == 8 and ctx.x64 and p == "I" then local imm1 = getimm(ctx, pos, 4); if not imm1 then return end local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end x = format("0x%08x%08x", imm2, imm1) else if n == 8 then n = 4 end local imm = getimm(ctx, pos, n); if not imm then return end if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then imm = (0xffffffff+1)-imm x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm) else x = format(imm > 65535 and "0x%08x" or "0x%x", imm) end end pos = pos+n elseif p == "j" then local n = map_sz2n[sz] if n == 8 then n = 4 end local imm = getimm(ctx, pos, n); if not imm then return end if sz == "B" and imm > 127 then imm = imm-256 elseif imm > 2147483647 then imm = imm-4294967296 end pos = pos+n imm = imm + pos + ctx.addr if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end ctx.imm = imm if sz == "W" then x = format("word 0x%04x", imm%65536) elseif ctx.x64 then local lo = imm % 0x1000000 x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo) else x = "0x"..tohex(imm) end elseif p == "R" then local r = byte(code, pos-1, pos-1)%8 if ctx.rexb then r = r + 8; ctx.rexb = false end x = regs[r+1] elseif p == "a" then x = regs[1] elseif p == "c" then x = "cl" elseif p == "d" then x = "dx" elseif p == "1" then x = "1" else if not mode then mode = ctx.mrm if not mode then if pos > stop then return incomplete(ctx) end mode = byte(code, pos, pos) pos = pos+1 end rm = mode%8; mode = (mode-rm)/8 sp = mode%8; mode = (mode-sp)/8 sdisp = "" if mode < 3 then if rm == 4 then if pos > stop then return incomplete(ctx) end sc = byte(code, pos, pos) pos = pos+1 rm = sc%8; sc = (sc-rm)/8 rx = sc%8; sc = (sc-rx)/8 if ctx.rexx then rx = rx + 8; ctx.rexx = false end if rx == 4 then rx = nil end end if mode > 0 or rm == 5 then local dsz = mode if dsz ~= 1 then dsz = 4 end local disp = getimm(ctx, pos, dsz); if not disp then return end if mode == 0 then rm = nil end if rm or rx or (not sc and ctx.x64 and not ctx.a32) then if dsz == 1 and disp > 127 then sdisp = format("-0x%x", 256-disp) elseif disp >= 0 and disp <= 0x7fffffff then sdisp = format("+0x%x", disp) else sdisp = format("-0x%x", (0xffffffff+1)-disp) end else sdisp = format(ctx.x64 and not ctx.a32 and not (disp >= 0 and disp <= 0x7fffffff) and "0xffffffff%08x" or "0x%08x", disp) end pos = pos+dsz end end if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end if ctx.rexr then sp = sp + 8; ctx.rexr = false end end if p == "m" then if mode == 3 then x = regs[rm+1] else local aregs = ctx.a32 and map_regs.D or ctx.aregs local srm, srx = "", "" if rm then srm = aregs[rm+1] elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end ctx.a32 = false if rx then if rm then srm = srm.."+" end srx = aregs[rx+1] if sc > 0 then srx = srx.."*"..(2^sc) end end x = format("[%s%s%s]", srm, srx, sdisp) end if mode < 3 and (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck. x = map_sz2prefix[sz].." "..x end elseif p == "r" then x = regs[sp+1] elseif p == "g" then x = map_segregs[sp+1] elseif p == "p" then -- Suppress prefix. elseif p == "f" then x = "st"..rm elseif p == "x" then if sp == 0 and ctx.lock and not ctx.x64 then x = "CR8"; ctx.lock = false else x = "CR"..sp end elseif p == "v" then if ctx.vexv then x = regs[ctx.vexv+1]; ctx.vexv = false end elseif p == "y" then x = "DR"..sp elseif p == "z" then x = "TR"..sp elseif p == "l" then vexl = false elseif p == "t" then else error("bad pattern `"..pat.."'") end end if x then operands = operands and operands..", "..x or x end end ctx.pos = pos return putop(ctx, name, operands) end -- Forward declaration. local map_act -- Fetch and cache MRM byte. local function getmrm(ctx) local mrm = ctx.mrm if not mrm then local pos = ctx.pos if pos > ctx.stop then return nil end mrm = byte(ctx.code, pos, pos) ctx.pos = pos+1 ctx.mrm = mrm end return mrm end -- Dispatch to handler depending on pattern. local function dispatch(ctx, opat, patgrp) if not opat then return unknown(ctx) end if match(opat, "%|") then -- MMX/SSE variants depending on prefix. local p if ctx.rep then p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)" ctx.rep = false elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false else p = "^[^%|]*" end opat = match(opat, p) if not opat then return unknown(ctx) end -- ctx.rep = false; ctx.o16 = false --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi] --XXX remove in branches? end if match(opat, "%$") then -- reg$mem variants. local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)") if opat == "" then return unknown(ctx) end end if opat == "" then return unknown(ctx) end local name, pat = match(opat, "^([a-z0-9 ]*)(.*)") if pat == "" and patgrp then pat = patgrp end return map_act[sub(pat, 1, 1)](ctx, name, pat) end -- Get a pattern from an opcode map and dispatch to handler. local function dispatchmap(ctx, opcmap) local pos = ctx.pos local opat = opcmap[byte(ctx.code, pos, pos)] pos = pos + 1 ctx.pos = pos return dispatch(ctx, opat) end -- Map for action codes. The key is the first char after the name. map_act = { -- Simple opcodes without operands. [""] = function(ctx, name, pat) return putop(ctx, name) end, -- Operand size chars fall right through. B = putpat, W = putpat, D = putpat, Q = putpat, V = putpat, U = putpat, T = putpat, M = putpat, X = putpat, P = putpat, F = putpat, G = putpat, Y = putpat, -- Collect prefixes. [":"] = function(ctx, name, pat) ctx[pat == ":" and name or sub(pat, 2)] = name if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes. end, -- Chain to special handler specified by name. ["*"] = function(ctx, name, pat) return map_act[name](ctx, name, sub(pat, 2)) end, -- Use named subtable for opcode group. ["!"] = function(ctx, name, pat) local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2)) end, -- o16,o32[,o64] variants. sz = function(ctx, name, pat) if ctx.o16 then ctx.o16 = false else pat = match(pat, ",(.*)") if ctx.rexw then local p = match(pat, ",(.*)") if p then pat = p; ctx.rexw = false end end end pat = match(pat, "^[^,]*") return dispatch(ctx, pat) end, -- Two-byte opcode dispatch. opc2 = function(ctx, name, pat) return dispatchmap(ctx, map_opc2) end, -- Three-byte opcode dispatch. opc3 = function(ctx, name, pat) return dispatchmap(ctx, map_opc3[pat]) end, -- VMX/SVM dispatch. vm = function(ctx, name, pat) return dispatch(ctx, map_opcvm[ctx.mrm]) end, -- Floating point opcode dispatch. fp = function(ctx, name, pat) local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end local rm = mrm%8 local idx = pat*8 + ((mrm-rm)/8)%8 if mrm >= 192 then idx = idx + 64 end local opat = map_opcfp[idx] if type(opat) == "table" then opat = opat[rm+1] end return dispatch(ctx, opat) end, -- REX prefix. rex = function(ctx, name, pat) if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed. for p in gmatch(pat, ".") do ctx["rex"..p] = true end ctx.rex = "rex" end, -- VEX prefix. vex = function(ctx, name, pat) if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed. ctx.rex = "vex" local pos = ctx.pos if ctx.mrm then ctx.mrm = nil pos = pos-1 end local b = byte(ctx.code, pos, pos) if not b then return incomplete(ctx) end pos = pos+1 if b < 128 then ctx.rexr = true end local m = 1 if pat == "3" then m = b%32; b = (b-m)/32 local nb = b%2; b = (b-nb)/2 if nb == 0 then ctx.rexb = true end local nx = b%2 if nx == 0 then ctx.rexx = true end b = byte(ctx.code, pos, pos) if not b then return incomplete(ctx) end pos = pos+1 if b >= 128 then ctx.rexw = true end end ctx.pos = pos local map if m == 1 then map = map_opc2 elseif m == 2 then map = map_opc3["38"] elseif m == 3 then map = map_opc3["3a"] else return unknown(ctx) end local p = b%4; b = (b-p)/4 if p == 1 then ctx.o16 = "o16" elseif p == 2 then ctx.rep = "rep" elseif p == 3 then ctx.rep = "repne" end local l = b%2; b = (b-l)/2 if l ~= 0 then ctx.vexl = true end ctx.vexv = (-1-b)%16 return dispatchmap(ctx, map) end, -- Special case for nop with REX prefix. nop = function(ctx, name, pat) return dispatch(ctx, ctx.rex and pat or "nop") end, -- Special case for 0F 77. emms = function(ctx, name, pat) if ctx.rex ~= "vex" then return putop(ctx, "emms") elseif ctx.vexl then ctx.vexl = false return putop(ctx, "zeroall") else return putop(ctx, "zeroupper") end end, } ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code ofs = ofs + 1 ctx.start = ofs ctx.pos = ofs ctx.stop = stop ctx.imm = nil ctx.mrm = false clearprefixes(ctx) while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end if ctx.pos ~= ctx.start then incomplete(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = (addr or 0) - 1 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 16 ctx.x64 = false ctx.map1 = map_opc1_32 ctx.aregs = map_regs.D return ctx end local function create64(code, addr, out) local ctx = create(code, addr, out) ctx.x64 = true ctx.map1 = map_opc1_64 ctx.aregs = map_regs.Q return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end local function disass64(code, addr, out) create64(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 8 then return map_regs.D[r+1] end return map_regs.X[r-7] end local function regname64(r) if r < 16 then return map_regs.Q[r+1] end return map_regs.X[r-15] end -- Public module functions. return { create = create, create64 = create64, disass = disass, disass64 = disass64, regname = regname, regname64 = regname64 } jit/dis_mips64.lua 0000644 00000001302 15027445263 0010022 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT MIPS64 disassembler wrapper module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This module just exports the big-endian functions from the -- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------ local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") return { create = dis_mips.create, disass = dis_mips.disass, regname = dis_mips.regname } jit/dis_mips.lua 0000644 00000032715 15027445263 0007664 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT MIPS disassembler module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT/X license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- It disassembles all standard MIPS32R1/R2 instructions. -- Default mode is big-endian, but see: dis_mipsel.lua ------------------------------------------------------------------------------ local type = type local byte, format = string.byte, string.format local match, gmatch = string.match, string.gmatch local concat = table.concat local bit = require("bit") local band, bor, tohex = bit.band, bit.bor, bit.tohex local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift ------------------------------------------------------------------------------ -- Primary and extended opcode maps ------------------------------------------------------------------------------ local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } local map_special = { shift = 0, mask = 63, [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" }, map_movci, map_srl, "sraDTA", "sllvDTS", false, map_srlv, "sravDTS", "jrS", "jalrD1S", "movzDST", "movnDST", "syscallY", "breakY", false, "sync", "mfhiD", "mthiS", "mfloD", "mtloS", "dsllvDST", false, "dsrlvDST", "dsravDST", "multST", "multuST", "divST", "divuST", "dmultST", "dmultuST", "ddivST", "ddivuST", "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T", "andDST", "or|moveDST0", "xorDST", "nor|notDST0", false, false, "sltDST", "sltuDST", "daddDST", "dadduDST", "dsubDST", "dsubuDST", "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ", "teqSTZ", false, "tneSTZ", false, "dsllDTA", false, "dsrlDTA", "dsraDTA", "dsll32DTA", false, "dsrl32DTA", "dsra32DTA", } local map_special2 = { shift = 0, mask = 63, [0] = "maddST", "madduST", "mulDST", false, "msubST", "msubuST", [32] = "clzDS", [33] = "cloDS", [63] = "sdbbpY", } local map_bshfl = { shift = 6, mask = 31, [2] = "wsbhDT", [16] = "sebDT", [24] = "sehDT", } local map_dbshfl = { shift = 6, mask = 31, [2] = "dsbhDT", [5] = "dshdDT", } local map_special3 = { shift = 0, mask = 63, [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK", [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL", [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD", } local map_regimm = { shift = 16, mask = 31, [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB", false, false, false, false, "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI", "teqiSI", false, "tneiSI", false, "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB", false, false, false, false, false, false, false, false, false, false, false, "synciSO", } local map_cop0 = { shift = 25, mask = 1, [0] = { shift = 21, mask = 15, [0] = "mfc0TDW", [4] = "mtc0TDW", [10] = "rdpgprDT", [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", }, [14] = "wrpgprDT", }, { shift = 0, mask = 63, [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp", [24] = "eret", [31] = "deret", [32] = "wait", }, } local map_cop1s = { shift = 0, mask = 63, [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH", "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG", "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG", "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG", false, { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" }, "movz.sFGT", "movn.sFGT", false, "recip.sFG", "rsqrt.sFG", false, false, false, false, false, false, false, false, false, false, "cvt.d.sFG", false, false, "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false, false, false, false, false, false, false, false, false, "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH", "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH", "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH", "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH", } local map_cop1d = { shift = 0, mask = 63, [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH", "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG", "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG", "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG", false, { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" }, "movz.dFGT", "movn.dFGT", false, "recip.dFG", "rsqrt.dFG", false, false, false, false, false, false, false, false, false, "cvt.s.dFG", false, false, false, "cvt.w.dFG", "cvt.l.dFG", false, false, false, false, false, false, false, false, false, false, "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH", "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH", "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH", "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH", } local map_cop1ps = { shift = 0, mask = 63, [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false, false, "abs.psFG", "mov.psFG", "neg.psFG", false, false, false, false, false, false, false, false, false, { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" }, "movz.psFGT", "movn.psFGT", false, false, false, false, false, false, false, false, false, false, false, false, "cvt.s.puFG", false, false, false, false, false, false, false, "cvt.s.plFG", false, false, false, "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH", "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH", "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH", "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH", "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH", } local map_cop1w = { shift = 0, mask = 63, [32] = "cvt.s.wFG", [33] = "cvt.d.wFG", } local map_cop1l = { shift = 0, mask = 63, [32] = "cvt.s.lFG", [33] = "cvt.d.lFG", } local map_cop1bc = { shift = 16, mask = 3, [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB", } local map_cop1 = { shift = 21, mask = 31, [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG", "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG", map_cop1bc, false, false, false, false, false, false, false, map_cop1s, map_cop1d, false, false, map_cop1w, map_cop1l, map_cop1ps, } local map_cop1x = { shift = 0, mask = 63, [0] = "lwxc1FSX", "ldxc1FSX", false, false, false, "luxc1FSX", false, false, "swxc1FSX", "sdxc1FSX", false, false, false, "suxc1FSX", false, "prefxMSX", false, false, false, false, false, false, false, false, false, false, false, false, false, false, "alnv.psFGHS", false, "madd.sFRGH", "madd.dFRGH", false, false, false, false, "madd.psFRGH", false, "msub.sFRGH", "msub.dFRGH", false, false, false, false, "msub.psFRGH", false, "nmadd.sFRGH", "nmadd.dFRGH", false, false, false, false, "nmadd.psFRGH", false, "nmsub.sFRGH", "nmsub.dFRGH", false, false, false, false, "nmsub.psFRGH", false, } local map_pri = { [0] = map_special, map_regimm, "jJ", "jalJ", "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB", "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI", "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU", map_cop0, map_cop1, false, map_cop1x, "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB", "daddiTSI", "daddiuTSI", false, false, map_special2, "jalxJ", false, map_special3, "lbTSO", "lhTSO", "lwlTSO", "lwTSO", "lbuTSO", "lhuTSO", "lwrTSO", false, "sbTSO", "shTSO", "swlTSO", "swTSO", false, false, "swrTSO", "cacheNSO", "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO", false, "ldc1HSO", "ldc2TSO", "ldTSO", "scTSO", "swc1HSO", "swc2TSO", false, false, "sdc1HSO", "sdc2TSO", "sdTSO", } ------------------------------------------------------------------------------ local map_gpr = { [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra", } ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local pos = ctx.pos local extra = "" if ctx.rel then local sym = ctx.symtab[ctx.rel] if sym then extra = "\t->"..sym end end if ctx.hexdump > 0 then ctx.out(format("%08x %s %-7s %s%s\n", ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) else ctx.out(format("%08x %-7s %s%s\n", ctx.addr+pos, text, concat(operands, ", "), extra)) end ctx.pos = pos + 4 end -- Fallback for unknown opcodes. local function unknown(ctx) return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) end local function get_be(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) end local function get_le(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) end -- Disassemble a single instruction. local function disass_ins(ctx) local op = ctx:get() local operands = {} local last = nil ctx.op = op ctx.rel = nil local opat = map_pri[rshift(op, 26)] while type(opat) ~= "string" do if not opat then return unknown(ctx) end opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ end local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") if altname then pat = pat2 end for p in gmatch(pat, ".") do local x = nil if p == "S" then x = map_gpr[band(rshift(op, 21), 31)] elseif p == "T" then x = map_gpr[band(rshift(op, 16), 31)] elseif p == "D" then x = map_gpr[band(rshift(op, 11), 31)] elseif p == "F" then x = "f"..band(rshift(op, 6), 31) elseif p == "G" then x = "f"..band(rshift(op, 11), 31) elseif p == "H" then x = "f"..band(rshift(op, 16), 31) elseif p == "R" then x = "f"..band(rshift(op, 21), 31) elseif p == "A" then x = band(rshift(op, 6), 31) elseif p == "E" then x = band(rshift(op, 6), 31) + 32 elseif p == "M" then x = band(rshift(op, 11), 31) elseif p == "N" then x = band(rshift(op, 16), 31) elseif p == "C" then x = band(rshift(op, 18), 7) if x == 0 then x = nil end elseif p == "K" then x = band(rshift(op, 11), 31) + 1 elseif p == "P" then x = band(rshift(op, 11), 31) + 33 elseif p == "L" then x = band(rshift(op, 11), 31) - last + 1 elseif p == "Q" then x = band(rshift(op, 11), 31) - last + 33 elseif p == "I" then x = arshift(lshift(op, 16), 16) elseif p == "U" then x = band(op, 0xffff) elseif p == "O" then local disp = arshift(lshift(op, 16), 16) operands[#operands] = format("%d(%s)", disp, last) elseif p == "X" then local index = map_gpr[band(rshift(op, 16), 31)] operands[#operands] = format("%s(%s)", index, last) elseif p == "B" then x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4 ctx.rel = x x = format("0x%08x", x) elseif p == "J" then local a = ctx.addr + ctx.pos x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4 ctx.rel = x x = format("0x%08x", x) elseif p == "V" then x = band(rshift(op, 8), 7) if x == 0 then x = nil end elseif p == "W" then x = band(op, 7) if x == 0 then x = nil end elseif p == "Y" then x = band(rshift(op, 6), 0x000fffff) if x == 0 then x = nil end elseif p == "Z" then x = band(rshift(op, 6), 1023) if x == 0 then x = nil end elseif p == "0" then if last == "r0" or last == 0 then local n = #operands operands[n] = nil last = operands[n-1] if altname then local a1, a2 = match(altname, "([^|]*)|(.*)") if a1 then name, altname = a1, a2 else name = altname end end end elseif p == "1" then if last == "ra" then operands[#operands] = nil end else assert(false) end if x then operands[#operands+1] = x; last = x end end return putop(ctx, name, operands) end ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code stop = stop - stop % 4 ctx.pos = ofs - ofs % 4 ctx.rel = nil while ctx.pos < stop do disass_ins(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = addr or 0 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 8 ctx.get = get_be return ctx end local function create_el(code, addr, out) local ctx = create(code, addr, out) ctx.get = get_le return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end local function disass_el(code, addr, out) create_el(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 32 then return map_gpr[r] end return "f"..(r-32) end -- Public module functions. return { create = create, create_el = create_el, disass = disass, disass_el = disass_el, regname = regname } jit/dump.lua 0000644 00000047334 15027445263 0007025 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT compiler dump module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module can be used to debug the JIT compiler itself. It dumps the -- code representations and structures used in various compiler stages. -- -- Example usage: -- -- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)" -- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R -- luajit -jdump=is myapp.lua | less -R -- luajit -jdump=-b myapp.lua -- luajit -jdump=+aH,myapp.html myapp.lua -- luajit -jdump=ixT,myapp.dump myapp.lua -- -- The first argument specifies the dump mode. The second argument gives -- the output file name. Default output is to stdout, unless the environment -- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the -- module is started. -- -- Different features can be turned on or off with the dump mode. If the -- mode starts with a '+', the following features are added to the default -- set of features; a '-' removes them. Otherwise the features are replaced. -- -- The following dump features are available (* marks the default): -- -- * t Print a line for each started, ended or aborted trace (see also -jv). -- * b Dump the traced bytecode. -- * i Dump the IR (intermediate representation). -- r Augment the IR with register/stack slots. -- s Dump the snapshot map. -- * m Dump the generated machine code. -- x Print each taken trace exit. -- X Print each taken trace exit and the contents of all registers. -- a Print the IR of aborted traces, too. -- -- The output format can be set with the following characters: -- -- T Plain text output. -- A ANSI-colored text output -- H Colorized HTML + CSS output. -- -- The default output format is plain text. It's set to ANSI-colored text -- if the COLORTERM variable is set. Note: this is independent of any output -- redirection, which is actually considered a feature. -- -- You probably want to use less -R to enjoy viewing ANSI-colored text from -- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R" -- ------------------------------------------------------------------------------ -- Cache some library functions and objects. local jit = require("jit") assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") local jutil = require("jit.util") local vmdef = require("jit.vmdef") local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr local bit = require("bit") local band, shr, tohex = bit.band, bit.rshift, bit.tohex local sub, gsub, format = string.sub, string.gsub, string.format local byte, rep = string.byte, string.rep local type, tostring = type, tostring local stdout, stderr = io.stdout, io.stderr -- Load other modules on-demand. local bcline, disass -- Active flag, output file handle and dump mode. local active, out, dumpmode ------------------------------------------------------------------------------ local symtabmt = { __index = false } local symtab = {} local nexitsym = 0 -- Fill nested symbol table with per-trace exit stub addresses. local function fillsymtab_tr(tr, nexit) local t = {} symtabmt.__index = t if jit.arch:sub(1, 4) == "mips" then t[traceexitstub(tr, 0)] = "exit" return end for i=0,nexit-1 do local addr = traceexitstub(tr, i) if addr < 0 then addr = addr + 2^32 end t[addr] = tostring(i) end local addr = traceexitstub(tr, nexit) if addr then t[addr] = "stack_check" end end -- Fill symbol table with trace exit stub addresses. local function fillsymtab(tr, nexit) local t = symtab if nexitsym == 0 then local ircall = vmdef.ircall for i=0,#ircall do local addr = ircalladdr(i) if addr ~= 0 then if addr < 0 then addr = addr + 2^32 end t[addr] = ircall[i] end end end if nexitsym == 1000000 then -- Per-trace exit stubs. fillsymtab_tr(tr, nexit) elseif nexit > nexitsym then -- Shared exit stubs. for i=nexitsym,nexit-1 do local addr = traceexitstub(i) if addr == nil then -- Fall back to per-trace exit stubs. fillsymtab_tr(tr, nexit) setmetatable(symtab, symtabmt) nexit = 1000000 break end if addr < 0 then addr = addr + 2^32 end t[addr] = tostring(i) end nexitsym = nexit end return t end local function dumpwrite(s) out:write(s) end -- Disassemble machine code. local function dump_mcode(tr) local info = traceinfo(tr) if not info then return end local mcode, addr, loop = tracemc(tr) if not mcode then return end if not disass then disass = require("jit.dis_"..jit.arch) end if addr < 0 then addr = addr + 2^32 end out:write("---- TRACE ", tr, " mcode ", #mcode, "\n") local ctx = disass.create(mcode, addr, dumpwrite) ctx.hexdump = 0 ctx.symtab = fillsymtab(tr, info.nexit) if loop ~= 0 then symtab[addr+loop] = "LOOP" ctx:disass(0, loop) out:write("->LOOP:\n") ctx:disass(loop, #mcode-loop) symtab[addr+loop] = nil else ctx:disass(0, #mcode) end end ------------------------------------------------------------------------------ local irtype_text = { [0] = "nil", "fal", "tru", "lud", "str", "p32", "thr", "pro", "fun", "p64", "cdt", "tab", "udt", "flt", "num", "i8 ", "u8 ", "i16", "u16", "int", "u32", "i64", "u64", "sfp", } local colortype_ansi = { [0] = "%s", "%s", "%s", "\027[36m%s\027[m", "\027[32m%s\027[m", "%s", "\027[1m%s\027[m", "%s", "\027[1m%s\027[m", "%s", "\027[33m%s\027[m", "\027[31m%s\027[m", "\027[36m%s\027[m", "\027[34m%s\027[m", "\027[34m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", "\027[35m%s\027[m", } local function colorize_text(s) return s end local function colorize_ansi(s, t) return format(colortype_ansi[t], s) end local irtype_ansi = setmetatable({}, { __index = function(tab, t) local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end }) local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", } local function colorize_html(s, t) s = gsub(s, "[<>&]", html_escape) return format('<span class="irt_%s">%s</span>', irtype_text[t], s) end local irtype_html = setmetatable({}, { __index = function(tab, t) local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end }) local header_html = [[ <style type="text/css"> background { background: #ffffff; color: #000000; } pre.ljdump { font-size: 10pt; background: #f0f4ff; color: #000000; border: 1px solid #bfcfff; padding: 0.5em; margin-left: 2em; margin-right: 2em; } span.irt_str { color: #00a000; } span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; } span.irt_tab { color: #c00000; } span.irt_udt, span.irt_lud { color: #00c0c0; } span.irt_num { color: #4040c0; } span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; } </style> ]] local colorize, irtype -- Lookup tables to convert some literals into names. local litname = { ["SLOAD "] = setmetatable({}, { __index = function(t, mode) local s = "" if band(mode, 1) ~= 0 then s = s.."P" end if band(mode, 2) ~= 0 then s = s.."F" end if band(mode, 4) ~= 0 then s = s.."T" end if band(mode, 8) ~= 0 then s = s.."C" end if band(mode, 16) ~= 0 then s = s.."R" end if band(mode, 32) ~= 0 then s = s.."I" end t[mode] = s return s end}), ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", }, ["CONV "] = setmetatable({}, { __index = function(t, mode) local s = irtype[band(mode, 31)] s = irtype[band(shr(mode, 5), 31)].."."..s if band(mode, 0x800) ~= 0 then s = s.." sext" end local c = shr(mode, 14) if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end t[mode] = s return s end}), ["FLOAD "] = vmdef.irfield, ["FREF "] = vmdef.irfield, ["FPMATH"] = vmdef.irfpm, ["BUFHDR"] = { [0] = "RESET", "APPEND" }, ["TOSTR "] = { [0] = "INT", "NUM", "CHAR" }, } local function ctlsub(c) if c == "\n" then return "\\n" elseif c == "\r" then return "\\r" elseif c == "\t" then return "\\t" else return format("\\%03d", byte(c)) end end local function fmtfunc(func, pc) local fi = funcinfo(func, pc) if fi.loc then return fi.loc elseif fi.ffid then return vmdef.ffnames[fi.ffid] elseif fi.addr then return format("C:%x", fi.addr) else return "(?)" end end local function formatk(tr, idx, sn) local k, t, slot = tracek(tr, idx) local tn = type(k) local s if tn == "number" then if t < 12 then s = k == 0 and "NULL" or format("[0x%08x]", k) elseif band(sn or 0, 0x30000) ~= 0 then s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz" elseif k == 2^52+2^51 then s = "bias" else s = format(0 < k and k < 0x1p-1026 and "%+a" or "%+.14g", k) end elseif tn == "string" then s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub)) elseif tn == "function" then s = fmtfunc(k) elseif tn == "table" then s = format("{%p}", k) elseif tn == "userdata" then if t == 12 then s = format("userdata:%p", k) else s = format("[%p]", k) if s == "[NULL]" then s = "NULL" end end elseif t == 21 then -- int64_t s = sub(tostring(k), 1, -3) if sub(s, 1, 1) ~= "-" then s = "+"..s end elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL) return "----" -- Special case for LJ_FR2 slot 1. else s = tostring(k) -- For primitives. end s = colorize(format("%-4s", s), t) if slot then s = format("%s @%d", s, slot) end return s end local function printsnap(tr, snap) local n = 2 for s=0,snap[1]-1 do local sn = snap[n] if shr(sn, 24) == s then n = n + 1 local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS if ref < 0 then out:write(formatk(tr, ref, sn)) elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM out:write(colorize(format("%04d/%04d", ref, ref+1), 14)) else local m, ot, op1, op2 = traceir(tr, ref) out:write(colorize(format("%04d", ref), band(ot, 31))) end out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME else out:write("---- ") end end out:write("]\n") end -- Dump snapshots (not interleaved with IR). local function dump_snap(tr) out:write("---- TRACE ", tr, " snapshots\n") for i=0,1000000000 do local snap = tracesnap(tr, i) if not snap then break end out:write(format("#%-3d %04d [ ", i, snap[0])) printsnap(tr, snap) end end -- Return a register name or stack slot for a rid/sp location. local function ridsp_name(ridsp, ins) if not disass then disass = require("jit.dis_"..jit.arch) end local rid, slot = band(ridsp, 0xff), shr(ridsp, 8) if rid == 253 or rid == 254 then return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot) end if ridsp > 255 then return format("[%x]", slot*4) end if rid < 128 then return disass.regname(rid) end return "" end -- Dump CALL* function ref and return optional ctype. local function dumpcallfunc(tr, ins) local ctype if ins > 0 then local m, ot, op1, op2 = traceir(tr, ins) if band(ot, 31) == 0 then -- nil type means CARG(func, ctype). ins = op1 ctype = formatk(tr, op2) end end if ins < 0 then out:write(format("[0x%x](", tonumber((tracek(tr, ins))))) else out:write(format("%04d (", ins)) end return ctype end -- Recursively gather CALL* args and dump them. local function dumpcallargs(tr, ins) if ins < 0 then out:write(formatk(tr, ins)) else local m, ot, op1, op2 = traceir(tr, ins) local oidx = 6*shr(ot, 8) local op = sub(vmdef.irnames, oidx+1, oidx+6) if op == "CARG " then dumpcallargs(tr, op1) if op2 < 0 then out:write(" ", formatk(tr, op2)) else out:write(" ", format("%04d", op2)) end else out:write(format("%04d", ins)) end end end -- Dump IR and interleaved snapshots. local function dump_ir(tr, dumpsnap, dumpreg) local info = traceinfo(tr) if not info then return end local nins = info.nins out:write("---- TRACE ", tr, " IR\n") local irnames = vmdef.irnames local snapref = 65536 local snap, snapno if dumpsnap then snap = tracesnap(tr, 0) snapref = snap[0] snapno = 0 end for ins=1,nins do if ins >= snapref then if dumpreg then out:write(format(".... SNAP #%-3d [ ", snapno)) else out:write(format(".... SNAP #%-3d [ ", snapno)) end printsnap(tr, snap) snapno = snapno + 1 snap = tracesnap(tr, snapno) snapref = snap and snap[0] or 65536 end local m, ot, op1, op2, ridsp = traceir(tr, ins) local oidx, t = 6*shr(ot, 8), band(ot, 31) local op = sub(irnames, oidx+1, oidx+6) if op == "LOOP " then if dumpreg then out:write(format("%04d ------------ LOOP ------------\n", ins)) else out:write(format("%04d ------ LOOP ------------\n", ins)) end elseif op ~= "NOP " and op ~= "CARG " and (dumpreg or op ~= "RENAME") then local rid = band(ridsp, 255) if dumpreg then out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins))) else out:write(format("%04d ", ins)) end out:write(format("%s%s %s %s ", (rid == 254 or rid == 253) and "}" or (band(ot, 128) == 0 and " " or ">"), band(ot, 64) == 0 and " " or "+", irtype[t], op)) local m1, m2 = band(m, 3), band(m, 3*4) if sub(op, 1, 4) == "CALL" then local ctype if m2 == 1*4 then -- op2 == IRMlit out:write(format("%-10s (", vmdef.ircall[op2])) else ctype = dumpcallfunc(tr, op2) end if op1 ~= -1 then dumpcallargs(tr, op1) end out:write(")") if ctype then out:write(" ctype ", ctype) end elseif op == "CNEW " and op2 == -1 then out:write(formatk(tr, op1)) elseif m1 ~= 3 then -- op1 != IRMnone if op1 < 0 then out:write(formatk(tr, op1)) else out:write(format(m1 == 0 and "%04d" or "#%-3d", op1)) end if m2 ~= 3*4 then -- op2 != IRMnone if m2 == 1*4 then -- op2 == IRMlit local litn = litname[op] if litn and litn[op2] then out:write(" ", litn[op2]) elseif op == "UREFO " or op == "UREFC " then out:write(format(" #%-3d", shr(op2, 8))) else out:write(format(" #%-3d", op2)) end elseif op2 < 0 then out:write(" ", formatk(tr, op2)) else out:write(format(" %04d", op2)) end end end out:write("\n") end end if snap then if dumpreg then out:write(format(".... SNAP #%-3d [ ", snapno)) else out:write(format(".... SNAP #%-3d [ ", snapno)) end printsnap(tr, snap) end end ------------------------------------------------------------------------------ local recprefix = "" local recdepth = 0 -- Format trace error message. local function fmterr(err, info) if type(err) == "number" then if type(info) == "function" then info = fmtfunc(info) end err = format(vmdef.traceerr[err], info) end return err end -- Dump trace states. local function dump_trace(what, tr, func, pc, otr, oex) if what == "stop" or (what == "abort" and dumpmode.a) then if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop") elseif dumpmode.s then dump_snap(tr) end if dumpmode.m then dump_mcode(tr) end end if what == "start" then if dumpmode.H then out:write('<pre class="ljdump">\n') end out:write("---- TRACE ", tr, " ", what) if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end out:write(" ", fmtfunc(func, pc), "\n") elseif what == "stop" or what == "abort" then out:write("---- TRACE ", tr, " ", what) if what == "abort" then out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n") else local info = traceinfo(tr) local link, ltype = info.link, info.linktype if link == tr or link == 0 then out:write(" -> ", ltype, "\n") elseif ltype == "root" then out:write(" -> ", link, "\n") else out:write(" -> ", link, " ", ltype, "\n") end end if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end else if what == "flush" then symtab, nexitsym = {}, 0 end out:write("---- TRACE ", what, "\n\n") end out:flush() end -- Dump recorded bytecode. local function dump_record(tr, func, pc, depth, callee) if depth ~= recdepth then recdepth = depth recprefix = rep(" .", depth) end local line if pc >= 0 then line = bcline(func, pc, recprefix) if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end else line = "0000 "..recprefix.." FUNCC \n" callee = func end if pc <= 0 then out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n") else out:write(line) end if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond. end end ------------------------------------------------------------------------------ -- Dump taken trace exits. local function dump_texit(tr, ex, ngpr, nfpr, ...) out:write("---- TRACE ", tr, " exit ", ex, "\n") if dumpmode.X then local regs = {...} if jit.arch == "x64" then for i=1,ngpr do out:write(format(" %016x", regs[i])) if i % 4 == 0 then out:write("\n") end end else for i=1,ngpr do out:write(" ", tohex(regs[i])) if i % 8 == 0 then out:write("\n") end end end if jit.arch == "mips" or jit.arch == "mipsel" then for i=1,nfpr,2 do out:write(format(" %+17.14g", regs[ngpr+i])) if i % 8 == 7 then out:write("\n") end end else for i=1,nfpr do out:write(format(" %+17.14g", regs[ngpr+i])) if i % 4 == 0 then out:write("\n") end end end end end ------------------------------------------------------------------------------ -- Detach dump handlers. local function dumpoff() if active then active = false jit.attach(dump_texit) jit.attach(dump_record) jit.attach(dump_trace) if out and out ~= stdout and out ~= stderr then out:close() end out = nil end end -- Open the output file and attach dump handlers. local function dumpon(opt, outfile) if active then dumpoff() end local term = os.getenv("TERM") local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T" if opt then opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end) end local m = { t=true, b=true, i=true, m=true, } if opt and opt ~= "" then local o = sub(opt, 1, 1) if o ~= "+" and o ~= "-" then m = {} end for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end end dumpmode = m if m.t or m.b or m.i or m.s or m.m then jit.attach(dump_trace, "trace") end if m.b then jit.attach(dump_record, "record") if not bcline then bcline = require("jit.bc").line end end if m.x or m.X then jit.attach(dump_texit, "texit") end if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end if outfile then out = outfile == "-" and stdout or assert(io.open(outfile, "w")) else out = stdout end m[colormode] = true if colormode == "A" then colorize = colorize_ansi irtype = irtype_ansi elseif colormode == "H" then colorize = colorize_html irtype = irtype_html out:write(header_html) else colorize = colorize_text irtype = irtype_text end active = true end -- Public module functions. return { on = dumpon, off = dumpoff, start = dumpon -- For -j command line option. } jit/dis_mipsel.lua 0000644 00000001313 15027445263 0010173 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT MIPSEL disassembler wrapper module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This module just exports the little-endian functions from the -- MIPS disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------ local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips") return { create = dis_mips.create_el, disass = dis_mips.disass_el, regname = dis_mips.regname } jit/bc.lua 0000644 00000012764 15027445263 0006443 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT bytecode listing module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- -- This module lists the bytecode of a Lua function. If it's loaded by -jbc -- it hooks into the parser and lists all functions of a chunk as they -- are parsed. -- -- Example usage: -- -- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)' -- luajit -jbc=- foo.lua -- luajit -jbc=foo.list foo.lua -- -- Default output is to stderr. To redirect the output to a file, pass a -- filename as an argument (use '-' for stdout) or set the environment -- variable LUAJIT_LISTFILE. The file is overwritten every time the module -- is started. -- -- This module can also be used programmatically: -- -- local bc = require("jit.bc") -- -- local function foo() print("hello") end -- -- bc.dump(foo) --> -- BYTECODE -- [...] -- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" -- -- local out = { -- -- Do something with each line: -- write = function(t, ...) io.write(...) end, -- close = function(t) end, -- flush = function(t) end, -- } -- bc.dump(foo, out) -- ------------------------------------------------------------------------------ -- Cache some library functions and objects. local jit = require("jit") assert(jit.version_num == 20100, "LuaJIT core/library version mismatch") local jutil = require("jit.util") local vmdef = require("jit.vmdef") local bit = require("bit") local sub, gsub, format = string.sub, string.gsub, string.format local byte, band, shr = string.byte, bit.band, bit.rshift local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck local funcuvname = jutil.funcuvname local bcnames = vmdef.bcnames local stdout, stderr = io.stdout, io.stderr ------------------------------------------------------------------------------ local function ctlsub(c) if c == "\n" then return "\\n" elseif c == "\r" then return "\\r" elseif c == "\t" then return "\\t" else return format("\\%03d", byte(c)) end end -- Return one bytecode line. local function bcline(func, pc, prefix) local ins, m = funcbc(func, pc) if not ins then return end local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128) local a = band(shr(ins, 8), 0xff) local oidx = 6*band(ins, 0xff) local op = sub(bcnames, oidx+1, oidx+6) local s = format("%04d %s %-6s %3s ", pc, prefix or " ", op, ma == 0 and "" or a) local d = shr(ins, 16) if mc == 13*128 then -- BCMjump return format("%s=> %04d\n", s, pc+d-0x7fff) end if mb ~= 0 then d = band(d, 0xff) elseif mc == 0 then return s.."\n" end local kc if mc == 10*128 then -- BCMstr kc = funck(func, -d-1) kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub)) elseif mc == 9*128 then -- BCMnum kc = funck(func, d) if op == "TSETM " then kc = kc - 2^52 end elseif mc == 12*128 then -- BCMfunc local fi = funcinfo(funck(func, -d-1)) if fi.ffid then kc = vmdef.ffnames[fi.ffid] else kc = fi.loc end elseif mc == 5*128 then -- BCMuv kc = funcuvname(func, d) end if ma == 5 then -- BCMuv local ka = funcuvname(func, a) if kc then kc = ka.." ; "..kc else kc = ka end end if mb ~= 0 then local b = shr(ins, 24) if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end return format("%s%3d %3d\n", s, b, d) end if kc then return format("%s%3d ; %s\n", s, d, kc) end if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits return format("%s%3d\n", s, d) end -- Collect branch targets of a function. local function bctargets(func) local target = {} for pc=1,1000000000 do local ins, m = funcbc(func, pc) if not ins then break end if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end end return target end -- Dump bytecode instructions of a function. local function bcdump(func, out, all) if not out then out = stdout end local fi = funcinfo(func) if all and fi.children then for n=-1,-1000000000,-1 do local k = funck(func, n) if not k then break end if type(k) == "proto" then bcdump(k, out, true) end end end out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) local target = bctargets(func) for pc=1,1000000000 do local s = bcline(func, pc, target[pc] and "=>") if not s then break end out:write(s) end out:write("\n") out:flush() end ------------------------------------------------------------------------------ -- Active flag and output file handle. local active, out -- List handler. local function h_list(func) return bcdump(func, out) end -- Detach list handler. local function bclistoff() if active then active = false jit.attach(h_list) if out and out ~= stdout and out ~= stderr then out:close() end out = nil end end -- Open the output file and attach list handler. local function bcliston(outfile) if active then bclistoff() end if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end if outfile then out = outfile == "-" and stdout or assert(io.open(outfile, "w")) else out = stderr end jit.attach(h_list, "bc") active = true end -- Public module functions. return { line = bcline, dump = bcdump, targets = bctargets, on = bcliston, off = bclistoff, start = bcliston -- For -j command line option. } jit/dis_arm64.lua 0000644 00000074270 15027445263 0007647 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT ARM64 disassembler module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h -- -- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com. -- Sponsored by Cisco Systems, Inc. ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- It disassembles most user-mode AArch64 instructions. -- NYI: Advanced SIMD and VFP instructions. ------------------------------------------------------------------------------ local type = type local sub, byte, format = string.sub, string.byte, string.format local match, gmatch, gsub = string.match, string.gmatch, string.gsub local concat = table.concat local bit = require("bit") local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift local ror = bit.ror ------------------------------------------------------------------------------ -- Opcode maps ------------------------------------------------------------------------------ local map_adr = { -- PC-relative addressing. shift = 31, mask = 1, [0] = "adrDBx", "adrpDBx" } local map_addsubi = { -- Add/subtract immediate. shift = 29, mask = 3, [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg", } local map_logi = { -- Logical immediate. shift = 31, mask = 1, [0] = { shift = 22, mask = 1, [0] = { shift = 29, mask = 3, [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" }, false -- unallocated }, { shift = 29, mask = 3, [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig" } } local map_movwi = { -- Move wide immediate. shift = 31, mask = 1, [0] = { shift = 22, mask = 1, [0] = { shift = 29, mask = 3, [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" }, false -- unallocated }, { shift = 29, mask = 3, [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg" }, } local map_bitf = { -- Bitfield. shift = 31, mask = 1, [0] = { shift = 22, mask = 1, [0] = { shift = 29, mask = 3, [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w", "bfm|bfi|bfxilDN13w", "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w" } }, { shift = 22, mask = 1, { shift = 29, mask = 3, [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x", "bfm|bfi|bfxilDN13x", "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x" } } } local map_datai = { -- Data processing - immediate. shift = 23, mask = 7, [0] = map_adr, map_adr, map_addsubi, false, map_logi, map_movwi, map_bitf, { shift = 15, mask = 0x1c0c1, [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x", [0x10081] = "extr|rorDNM4x" } } local map_logsr = { -- Logical, shifted register. shift = 31, mask = 1, [0] = { shift = 15, mask = 1, [0] = { shift = 29, mask = 3, [0] = { shift = 21, mask = 7, [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" }, { shift = 21, mask = 7, [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" }, { shift = 21, mask = 7, [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" }, { shift = 21, mask = 7, [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" } }, false -- unallocated }, { shift = 29, mask = 3, [0] = { shift = 21, mask = 7, [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" }, { shift = 21, mask = 7, [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" }, { shift = 21, mask = 7, [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" }, { shift = 21, mask = 7, [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" } } } local map_assh = { shift = 31, mask = 1, [0] = { shift = 15, mask = 1, [0] = { shift = 29, mask = 3, [0] = { shift = 22, mask = 3, [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" }, { shift = 22, mask = 3, [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMg" }, { shift = 22, mask = 3, [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" }, { shift = 22, mask = 3, [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" }, }, false -- unallocated }, { shift = 29, mask = 3, [0] = { shift = 22, mask = 3, [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg" }, { shift = 22, mask = 3, [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMg" }, { shift = 22, mask = 3, [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg" }, { shift = 22, mask = 3, [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg" } } } local map_addsubsh = { -- Add/subtract, shifted register. shift = 22, mask = 3, [0] = map_assh, map_assh, map_assh } local map_addsubex = { -- Add/subtract, extended register. shift = 22, mask = 3, [0] = { shift = 29, mask = 3, [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg", } } local map_addsubc = { -- Add/subtract, with carry. shift = 10, mask = 63, [0] = { shift = 29, mask = 3, [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg", } } local map_ccomp = { shift = 4, mask = 1, [0] = { shift = 10, mask = 3, [0] = { -- Conditional compare register. shift = 29, mask = 3, "ccmnNMVCg", false, "ccmpNMVCg", }, [2] = { -- Conditional compare immediate. shift = 29, mask = 3, "ccmnN5VCg", false, "ccmpN5VCg", } } } local map_csel = { -- Conditional select. shift = 11, mask = 1, [0] = { shift = 10, mask = 1, [0] = { shift = 29, mask = 3, [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false, }, { shift = 29, mask = 3, [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false, } } } local map_data1s = { -- Data processing, 1 source. shift = 29, mask = 1, [0] = { shift = 31, mask = 1, [0] = { shift = 10, mask = 0x7ff, [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg" }, { shift = 10, mask = 0x7ff, [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg" } } } local map_data2s = { -- Data processing, 2 sources. shift = 29, mask = 1, [0] = { shift = 10, mask = 63, false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg", "lsrDNMg", "asrDNMg", "rorDNMg" } } local map_data3s = { -- Data processing, 3 sources. shift = 29, mask = 7, [0] = { shift = 21, mask = 7, [0] = { shift = 15, mask = 1, [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g" } }, false, false, false, { shift = 15, mask = 1, [0] = { shift = 21, mask = 7, [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false, false, "umaddl|umullDxNMwA0x", "umulhDNMx" }, { shift = 21, mask = 7, [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false, false, "umsubl|umneglDxNMwA0x" } } } local map_datar = { -- Data processing, register. shift = 28, mask = 1, [0] = { shift = 24, mask = 1, [0] = map_logsr, { shift = 21, mask = 1, [0] = map_addsubsh, map_addsubex } }, { shift = 21, mask = 15, [0] = map_addsubc, false, map_ccomp, false, map_csel, false, { shift = 30, mask = 1, [0] = map_data2s, map_data1s }, false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s } } local map_lrl = { -- Load register, literal. shift = 26, mask = 1, [0] = { shift = 30, mask = 3, [0] = "ldrDwB", "ldrDxB", "ldrswDxB" }, { shift = 30, mask = 3, [0] = "ldrDsB", "ldrDdB" } } local map_lsriind = { -- Load/store register, immediate pre/post-indexed. shift = 30, mask = 3, [0] = { shift = 26, mask = 1, [0] = { shift = 22, mask = 3, [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL" } }, { shift = 26, mask = 1, [0] = { shift = 22, mask = 3, [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL" } }, { shift = 26, mask = 1, [0] = { shift = 22, mask = 3, [0] = "strDwzL", "ldrDwzL", "ldrswDxzL" }, { shift = 22, mask = 3, [0] = "strDszL", "ldrDszL" } }, { shift = 26, mask = 1, [0] = { shift = 22, mask = 3, [0] = "strDxzL", "ldrDxzL" }, { shift = 22, mask = 3, [0] = "strDdzL", "ldrDdzL" } } } local map_lsriro = { shift = 21, mask = 1, [0] = { -- Load/store register immediate. shift = 10, mask = 3, [0] = { -- Unscaled immediate. shift = 26, mask = 1, [0] = { shift = 30, mask = 3, [0] = { shift = 22, mask = 3, [0] = "sturbDwK", "ldurbDwK" }, { shift = 22, mask = 3, [0] = "sturhDwK", "ldurhDwK" }, { shift = 22, mask = 3, [0] = "sturDwK", "ldurDwK" }, { shift = 22, mask = 3, [0] = "sturDxK", "ldurDxK" } } }, map_lsriind, false, map_lsriind }, { -- Load/store register, register offset. shift = 10, mask = 3, [2] = { shift = 26, mask = 1, [0] = { shift = 30, mask = 3, [0] = { shift = 22, mask = 3, [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO" }, { shift = 22, mask = 3, [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO" }, { shift = 22, mask = 3, [0] = "strDwO", "ldrDwO", "ldrswDxO" }, { shift = 22, mask = 3, [0] = "strDxO", "ldrDxO" } }, { shift = 30, mask = 3, [2] = { shift = 22, mask = 3, [0] = "strDsO", "ldrDsO" }, [3] = { shift = 22, mask = 3, [0] = "strDdO", "ldrDdO" } } } } } local map_lsp = { -- Load/store register pair, offset. shift = 22, mask = 1, [0] = { shift = 30, mask = 3, [0] = { shift = 26, mask = 1, [0] = "stpDzAzwP", "stpDzAzsP", }, { shift = 26, mask = 1, "stpDzAzdP" }, { shift = 26, mask = 1, [0] = "stpDzAzxP" } }, { shift = 30, mask = 3, [0] = { shift = 26, mask = 1, [0] = "ldpDzAzwP", "ldpDzAzsP", }, { shift = 26, mask = 1, [0] = "ldpswDAxP", "ldpDzAzdP" }, { shift = 26, mask = 1, [0] = "ldpDzAzxP" } } } local map_ls = { -- Loads and stores. shift = 24, mask = 0x31, [0x10] = map_lrl, [0x30] = map_lsriro, [0x20] = { shift = 23, mask = 3, map_lsp, map_lsp, map_lsp }, [0x21] = { shift = 23, mask = 3, map_lsp, map_lsp, map_lsp }, [0x31] = { shift = 26, mask = 1, [0] = { shift = 30, mask = 3, [0] = { shift = 22, mask = 3, [0] = "strbDwzU", "ldrbDwzU" }, { shift = 22, mask = 3, [0] = "strhDwzU", "ldrhDwzU" }, { shift = 22, mask = 3, [0] = "strDwzU", "ldrDwzU" }, { shift = 22, mask = 3, [0] = "strDxzU", "ldrDxzU" } }, { shift = 30, mask = 3, [2] = { shift = 22, mask = 3, [0] = "strDszU", "ldrDszU" }, [3] = { shift = 22, mask = 3, [0] = "strDdzU", "ldrDdzU" } } }, } local map_datafp = { -- Data processing, SIMD and FP. shift = 28, mask = 7, { -- 001 shift = 24, mask = 1, [0] = { shift = 21, mask = 1, { shift = 10, mask = 3, [0] = { shift = 12, mask = 1, [0] = { shift = 13, mask = 1, [0] = { shift = 14, mask = 1, [0] = { shift = 15, mask = 1, [0] = { -- FP/int conversion. shift = 31, mask = 1, [0] = { shift = 16, mask = 0xff, [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs", [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw", [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs", [0x26] = "fmovDwNs", [0x27] = "fmovDsNw", [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs", [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs", [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs", [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd", [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw", [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd", [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd", [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd", [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd" }, { shift = 16, mask = 0xff, [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs", [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx", [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs", [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs", [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs", [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs", [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd", [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx", [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd", [0x66] = "fmovDxNd", [0x67] = "fmovDdNx", [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd", [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd", [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd" } } }, { -- FP data-processing, 1 source. shift = 31, mask = 1, [0] = { shift = 22, mask = 3, [0] = { shift = 15, mask = 63, [0] = "fmovDNf", "fabsDNf", "fnegDNf", "fsqrtDNf", false, "fcvtDdNs", false, false, "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", "frintaDNf", false, "frintxDNf", "frintiDNf", }, { shift = 15, mask = 63, [0] = "fmovDNf", "fabsDNf", "fnegDNf", "fsqrtDNf", "fcvtDsNd", false, false, false, "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf", "frintaDNf", false, "frintxDNf", "frintiDNf", } } } }, { -- FP compare. shift = 31, mask = 1, [0] = { shift = 14, mask = 3, [0] = { shift = 23, mask = 1, [0] = { shift = 0, mask = 31, [0] = "fcmpNMf", [8] = "fcmpNZf", [16] = "fcmpeNMf", [24] = "fcmpeNZf", } } } } }, { -- FP immediate. shift = 31, mask = 1, [0] = { shift = 5, mask = 31, [0] = { shift = 23, mask = 1, [0] = "fmovDFf" } } } }, { -- FP conditional compare. shift = 31, mask = 1, [0] = { shift = 23, mask = 1, [0] = { shift = 4, mask = 1, [0] = "fccmpNMVCf", "fccmpeNMVCf" } } }, { -- FP data-processing, 2 sources. shift = 31, mask = 1, [0] = { shift = 23, mask = 1, [0] = { shift = 12, mask = 15, [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf", "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf", "fnmulDNMf" } } }, { -- FP conditional select. shift = 31, mask = 1, [0] = { shift = 23, mask = 1, [0] = "fcselDNMCf" } } } }, { -- FP data-processing, 3 sources. shift = 31, mask = 1, [0] = { shift = 15, mask = 1, [0] = { shift = 21, mask = 5, [0] = "fmaddDNMAf", "fnmaddDNMAf" }, { shift = 21, mask = 5, [0] = "fmsubDNMAf", "fnmsubDNMAf" } } } } } local map_br = { -- Branches, exception generating and system instructions. shift = 29, mask = 7, [0] = "bB", { -- Compare & branch, immediate. shift = 24, mask = 3, [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw" }, { -- Conditional branch, immediate. shift = 24, mask = 3, [0] = { shift = 4, mask = 1, [0] = { shift = 0, mask = 15, [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB", "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB" } } }, false, "blB", { -- Compare & branch, immediate. shift = 24, mask = 3, [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx" }, { shift = 24, mask = 3, [0] = { -- Exception generation. shift = 0, mask = 0xe0001f, [0x200000] = "brkW" }, { -- System instructions. shift = 0, mask = 0x3fffff, [0x03201f] = "nop" }, { -- Unconditional branch, register. shift = 0, mask = 0xfffc1f, [0x1f0000] = "brNx", [0x3f0000] = "blrNx", [0x5f0000] = "retNx" }, } } local map_init = { shift = 25, mask = 15, [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp, map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp } ------------------------------------------------------------------------------ local map_regs = { x = {}, w = {}, d = {}, s = {} } for i=0,30 do map_regs.x[i] = "x"..i map_regs.w[i] = "w"..i map_regs.d[i] = "d"..i map_regs.s[i] = "s"..i end map_regs.x[31] = "sp" map_regs.w[31] = "wsp" map_regs.d[31] = "d31" map_regs.s[31] = "s31" local map_cond = { [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", } local map_shift = { [0] = "lsl", "lsr", "asr", } local map_extend = { [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx", } ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local pos = ctx.pos local extra = "" if ctx.rel then local sym = ctx.symtab[ctx.rel] if sym then extra = "\t->"..sym end end if ctx.hexdump > 0 then ctx.out(format("%08x %s %-5s %s%s\n", ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) else ctx.out(format("%08x %-5s %s%s\n", ctx.addr+pos, text, concat(operands, ", "), extra)) end ctx.pos = pos + 4 end -- Fallback for unknown opcodes. local function unknown(ctx) return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) end local function match_reg(p, pat, regnum) return map_regs[match(pat, p.."%w-([xwds])")][regnum] end local function fmt_hex32(x) if x < 0 then return tohex(x) else return format("%x", x) end end local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 } local function decode_imm13(op) local imms = band(rshift(op, 10), 63) local immr = band(rshift(op, 16), 63) if band(op, 0x00400000) == 0 then local len = 5 if imms >= 56 then if imms >= 60 then len = 1 else len = 2 end elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end local l = lshift(1, len)-1 local s = band(imms, l) local r = band(immr, l) local imm = ror(rshift(-1, 31-s), r) if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end imm = imm * imm13_rep[len] local ix = fmt_hex32(imm) if rshift(op, 31) ~= 0 then return ix..tohex(imm) else return ix end else local lo, hi = -1, 0 if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end if immr ~= 0 then lo, hi = ror(lo, immr), ror(hi, immr) local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr)) lo, hi = bxor(lo, x), bxor(hi, x) if immr >= 32 then lo, hi = hi, lo end end if hi ~= 0 then return fmt_hex32(hi)..tohex(lo) else return fmt_hex32(lo) end end end local function parse_immpc(op, name) if name == "b" or name == "bl" then return arshift(lshift(op, 6), 4) elseif name == "adr" or name == "adrp" then local immlo = band(rshift(op, 29), 3) local immhi = lshift(arshift(lshift(op, 8), 13), 2) return bor(immhi, immlo) elseif name == "tbz" or name == "tbnz" then return lshift(arshift(lshift(op, 13), 18), 2) else return lshift(arshift(lshift(op, 8), 13), 2) end end local function parse_fpimm8(op) local sign = band(op, 0x100000) == 0 and 1 or -1 local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131 local frac = 16+band(rshift(op, 13), 15) return sign * frac * 2^exp end local function prefer_bfx(sf, uns, imms, immr) if imms < immr or imms == 31 or imms == 63 then return false end if immr == 0 then if sf == 0 and (imms == 7 or imms == 15) then return false end if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then return false end end return true end -- Disassemble a single instruction. local function disass_ins(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) local operands = {} local suffix = "" local last, name, pat local map_reg ctx.op = op ctx.rel = nil last = nil local opat opat = map_init[band(rshift(op, 25), 15)] while type(opat) ~= "string" do if not opat then return unknown(ctx) end opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ end name, pat = match(opat, "^([a-z0-9]*)(.*)") local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") if altname then pat = pat2 end if sub(pat, 1, 1) == "." then local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") suffix = suffix..s2 pat = p2 end local rt = match(pat, "[gf]") if rt then if rt == "g" then map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w else map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s end end local second0, immr for p in gmatch(pat, ".") do local x = nil if p == "D" then local regnum = band(op, 31) x = rt and map_reg[regnum] or match_reg(p, pat, regnum) elseif p == "N" then local regnum = band(rshift(op, 5), 31) x = rt and map_reg[regnum] or match_reg(p, pat, regnum) elseif p == "M" then local regnum = band(rshift(op, 16), 31) x = rt and map_reg[regnum] or match_reg(p, pat, regnum) elseif p == "A" then local regnum = band(rshift(op, 10), 31) x = rt and map_reg[regnum] or match_reg(p, pat, regnum) elseif p == "B" then local addr = ctx.addr + pos + parse_immpc(op, name) ctx.rel = addr x = "0x"..tohex(addr) elseif p == "T" then x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31)) elseif p == "V" then x = band(op, 15) elseif p == "C" then x = map_cond[band(rshift(op, 12), 15)] elseif p == "c" then local rn = band(rshift(op, 5), 31) local rm = band(rshift(op, 16), 31) local cond = band(rshift(op, 12), 15) local invc = bxor(cond, 1) x = map_cond[cond] if altname and cond ~= 14 and cond ~= 15 then local a1, a2 = match(altname, "([^|]*)|(.*)") if rn == rm then local n = #operands operands[n] = nil x = map_cond[invc] if rn ~= 31 then if a1 then name = a1 else name = altname end else operands[n-1] = nil name = a2 end end end elseif p == "W" then x = band(rshift(op, 5), 0xffff) elseif p == "Y" then x = band(rshift(op, 5), 0xffff) local hw = band(rshift(op, 21), 3) if altname and (hw == 0 or x ~= 0) then name = altname end elseif p == "L" then local rn = map_regs.x[band(rshift(op, 5), 31)] local imm9 = arshift(lshift(op, 11), 23) if band(op, 0x800) ~= 0 then x = "["..rn..", #"..imm9.."]!" else x = "["..rn.."], #"..imm9 end elseif p == "U" then local rn = map_regs.x[band(rshift(op, 5), 31)] local sz = band(rshift(op, 30), 3) local imm12 = lshift(arshift(lshift(op, 10), 20), sz) if imm12 ~= 0 then x = "["..rn..", #"..imm12.."]" else x = "["..rn.."]" end elseif p == "K" then local rn = map_regs.x[band(rshift(op, 5), 31)] local imm9 = arshift(lshift(op, 11), 23) if imm9 ~= 0 then x = "["..rn..", #"..imm9.."]" else x = "["..rn.."]" end elseif p == "O" then local rn, rm = map_regs.x[band(rshift(op, 5), 31)] local m = band(rshift(op, 13), 1) if m == 0 then rm = map_regs.w[band(rshift(op, 16), 31)] else rm = map_regs.x[band(rshift(op, 16), 31)] end x = "["..rn..", "..rm local opt = band(rshift(op, 13), 7) local s = band(rshift(op, 12), 1) local sz = band(rshift(op, 30), 3) -- extension to be applied if opt == 3 then if s == 0 then x = x.."]" else x = x..", lsl #"..sz.."]" end elseif opt == 2 or opt == 6 or opt == 7 then if s == 0 then x = x..", "..map_extend[opt].."]" else x = x..", "..map_extend[opt].." #"..sz.."]" end else x = x.."]" end elseif p == "P" then local opcv, sh = rshift(op, 26), 2 if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end local imm7 = lshift(arshift(lshift(op, 10), 25), sh) local rn = map_regs.x[band(rshift(op, 5), 31)] local ind = band(rshift(op, 23), 3) if ind == 1 then x = "["..rn.."], #"..imm7 elseif ind == 2 then if imm7 == 0 then x = "["..rn.."]" else x = "["..rn..", #"..imm7.."]" end elseif ind == 3 then x = "["..rn..", #"..imm7.."]!" end elseif p == "I" then local shf = band(rshift(op, 22), 3) local imm12 = band(rshift(op, 10), 0x0fff) local rn, rd = band(rshift(op, 5), 31), band(op, 31) if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then name = altname x = nil elseif shf == 0 then x = imm12 elseif shf == 1 then x = imm12..", lsl #12" end elseif p == "i" then x = "#0x"..decode_imm13(op) elseif p == "1" then immr = band(rshift(op, 16), 63) x = immr elseif p == "2" then x = band(rshift(op, 10), 63) if altname then local a1, a2, a3, a4, a5, a6 = match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)") local sf = band(rshift(op, 26), 32) local uns = band(rshift(op, 30), 1) if prefer_bfx(sf, uns, x, immr) then name = a2 x = x - immr + 1 elseif immr == 0 and x == 7 then local n = #operands operands[n] = nil if sf ~= 0 then operands[n-1] = gsub(operands[n-1], "x", "w") end last = operands[n-1] name = a6 x = nil elseif immr == 0 and x == 15 then local n = #operands operands[n] = nil if sf ~= 0 then operands[n-1] = gsub(operands[n-1], "x", "w") end last = operands[n-1] name = a5 x = nil elseif x == 31 or x == 63 then if x == 31 and immr == 0 and name == "sbfm" then name = a4 local n = #operands operands[n] = nil if sf ~= 0 then operands[n-1] = gsub(operands[n-1], "x", "w") end last = operands[n-1] else name = a3 end x = nil elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then name = a4 last = "#"..(sf+32 - immr) operands[#operands] = last x = nil elseif x < immr then name = a1 last = "#"..(sf+32 - immr) operands[#operands] = last x = x + 1 end end elseif p == "3" then x = band(rshift(op, 10), 63) if altname then local a1, a2 = match(altname, "([^|]*)|(.*)") if x < immr then name = a1 local sf = band(rshift(op, 26), 32) last = "#"..(sf+32 - immr) operands[#operands] = last x = x + 1 elseif x >= immr then name = a2 x = x - immr + 1 end end elseif p == "4" then x = band(rshift(op, 10), 63) local rn = band(rshift(op, 5), 31) local rm = band(rshift(op, 16), 31) if altname and rn == rm then local n = #operands operands[n] = nil last = operands[n-1] name = altname end elseif p == "5" then x = band(rshift(op, 16), 31) elseif p == "S" then x = band(rshift(op, 10), 63) if x == 0 then x = nil else x = map_shift[band(rshift(op, 22), 3)].." #"..x end elseif p == "X" then local opt = band(rshift(op, 13), 7) -- Width specifier <R>. if opt ~= 3 and opt ~= 7 then last = map_regs.w[band(rshift(op, 16), 31)] operands[#operands] = last end x = band(rshift(op, 10), 7) -- Extension. if opt == 2 + band(rshift(op, 31), 1) and band(rshift(op, second0 and 5 or 0), 31) == 31 then if x == 0 then x = nil else x = "lsl #"..x end else if x == 0 then x = map_extend[band(rshift(op, 13), 7)] else x = map_extend[band(rshift(op, 13), 7)].." #"..x end end elseif p == "R" then x = band(rshift(op,21), 3) if x == 0 then x = nil else x = "lsl #"..x*16 end elseif p == "z" then local n = #operands if operands[n] == "sp" then operands[n] = "xzr" elseif operands[n] == "wsp" then operands[n] = "wzr" end elseif p == "Z" then x = 0 elseif p == "F" then x = parse_fpimm8(op) elseif p == "g" or p == "f" or p == "x" or p == "w" or p == "d" or p == "s" then -- These are handled in D/N/M/A. elseif p == "0" then if last == "sp" or last == "wsp" then local n = #operands operands[n] = nil last = operands[n-1] if altname then local a1, a2 = match(altname, "([^|]*)|(.*)") if not a1 then name = altname elseif second0 then name, altname = a2, a1 else name, altname = a1, a2 end end end second0 = true else assert(false) end if x then last = x if type(x) == "number" then x = "#"..x end operands[#operands+1] = x end end return putop(ctx, name..suffix, operands) end ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code ctx.pos = ofs ctx.rel = nil while ctx.pos < stop do disass_ins(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = addr or 0 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 8 return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 32 then return map_regs.x[r] end return map_regs.d[r-32] end -- Public module functions. return { create = create, disass = disass, regname = regname } jit/dis_arm64be.lua 0000644 00000001153 15027445263 0010144 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT ARM64BE disassembler wrapper module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- ARM64 instructions are always little-endian. So just forward to the -- common ARM64 disassembler module. All the interesting stuff is there. ------------------------------------------------------------------------------ return require((string.match(..., ".*%.") or "").."dis_arm64") jit/dis_arm.lua 0000644 00000045620 15027445263 0007472 0 ustar 00 ---------------------------------------------------------------------------- -- LuaJIT ARM disassembler module. -- -- Copyright (C) 2005-2017 Mike Pall. All rights reserved. -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- It disassembles most user-mode ARMv7 instructions -- NYI: Advanced SIMD and VFP instructions. ------------------------------------------------------------------------------ local type = type local sub, byte, format = string.sub, string.byte, string.format local match, gmatch = string.match, string.gmatch local concat = table.concat local bit = require("bit") local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift ------------------------------------------------------------------------------ -- Opcode maps ------------------------------------------------------------------------------ local map_loadc = { shift = 8, mask = 15, [10] = { shift = 20, mask = 1, [0] = { shift = 23, mask = 3, [0] = "vmovFmDN", "vstmFNdr", _ = { shift = 21, mask = 1, [0] = "vstrFdl", { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", } }, }, { shift = 23, mask = 3, [0] = "vmovFDNm", { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", }, _ = { shift = 21, mask = 1, [0] = "vldrFdl", "vldmdbFNdr", }, }, }, [11] = { shift = 20, mask = 1, [0] = { shift = 23, mask = 3, [0] = "vmovGmDN", "vstmGNdr", _ = { shift = 21, mask = 1, [0] = "vstrGdl", { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", } }, }, { shift = 23, mask = 3, [0] = "vmovGDNm", { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", }, _ = { shift = 21, mask = 1, [0] = "vldrGdl", "vldmdbGNdr", }, }, }, _ = { shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc. }, } local map_vfps = { shift = 6, mask = 0x2c001, [0] = "vmlaF.dnm", "vmlsF.dnm", [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm", [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm", [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm", [0x20000] = "vdivF.dnm", [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm", [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm", [0x2c000] = "vmovF.dY", [0x2c001] = { shift = 7, mask = 0x1e01, [0] = "vmovF.dm", "vabsF.dm", [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm", [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm", [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d", [0x0e01] = "vcvtG.dF.m", [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm", [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm", [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm", }, } local map_vfpd = { shift = 6, mask = 0x2c001, [0] = "vmlaG.dnm", "vmlsG.dnm", [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm", [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm", [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm", [0x20000] = "vdivG.dnm", [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm", [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm", [0x2c000] = "vmovG.dY", [0x2c001] = { shift = 7, mask = 0x1e01, [0] = "vmovG.dm", "vabsG.dm", [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm", [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm", [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d", [0x0e01] = "vcvtF.dG.m", [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm", [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m", [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m", }, } local map_datac = { shift = 24, mask = 1, [0] = { shift = 4, mask = 1, [0] = { shift = 8, mask = 15, [10] = map_vfps, [11] = map_vfpd, -- NYI cdp, mcr, mrc. }, { shift = 8, mask = 15, [10] = { shift = 20, mask = 15, [0] = "vmovFnD", "vmovFDn", [14] = "vmsrD", [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", }, }, }, }, "svcT", } local map_loadcu = { shift = 0, mask = 0, -- NYI unconditional CP load/store. } local map_datacu = { shift = 0, mask = 0, -- NYI unconditional CP data. } local map_simddata = { shift = 0, mask = 0, -- NYI SIMD data. } local map_simdload = { shift = 0, mask = 0, -- NYI SIMD load/store, preload. } local map_preload = { shift = 0, mask = 0, -- NYI preload. } local map_media = { shift = 20, mask = 31, [0] = false, { --01 shift = 5, mask = 7, [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM", "sadd8DNM", false, false, "ssub8DNM", }, { --02 shift = 5, mask = 7, [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM", "qadd8DNM", false, false, "qsub8DNM", }, { --03 shift = 5, mask = 7, [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM", "shadd8DNM", false, false, "shsub8DNM", }, false, { --05 shift = 5, mask = 7, [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM", "uadd8DNM", false, false, "usub8DNM", }, { --06 shift = 5, mask = 7, [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM", "uqadd8DNM", false, false, "uqsub8DNM", }, { --07 shift = 5, mask = 7, [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM", "uhadd8DNM", false, false, "uhsub8DNM", }, { --08 shift = 5, mask = 7, [0] = "pkhbtDNMU", false, "pkhtbDNMU", { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", }, "pkhbtDNMU", "selDNM", "pkhtbDNMU", }, false, { --0a shift = 5, mask = 7, [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu", { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", }, "ssatDxMu", false, "ssatDxMu", }, { --0b shift = 5, mask = 7, [0] = "ssatDxMu", "revDM", "ssatDxMu", { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", }, "ssatDxMu", "rev16DM", "ssatDxMu", }, { --0c shift = 5, mask = 7, [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", }, }, false, { --0e shift = 5, mask = 7, [0] = "usatDwMu", "usat16DwM", "usatDwMu", { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", }, "usatDwMu", false, "usatDwMu", }, { --0f shift = 5, mask = 7, [0] = "usatDwMu", "rbitDM", "usatDwMu", { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", }, "usatDwMu", "revshDM", "usatDwMu", }, { --10 shift = 12, mask = 15, [15] = { shift = 5, mask = 7, "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS", }, _ = { shift = 5, mask = 7, [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD", }, }, false, false, false, { --14 shift = 5, mask = 7, [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS", }, { --15 shift = 5, mask = 7, [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", }, { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", }, false, false, false, false, "smmlsNMSD", "smmlsrNMSD", }, false, false, { --18 shift = 5, mask = 7, [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", }, }, false, { --1a shift = 5, mask = 3, [2] = "sbfxDMvw", }, { --1b shift = 5, mask = 3, [2] = "sbfxDMvw", }, { --1c shift = 5, mask = 3, [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, }, { --1d shift = 5, mask = 3, [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, }, { --1e shift = 5, mask = 3, [2] = "ubfxDMvw", }, { --1f shift = 5, mask = 3, [2] = "ubfxDMvw", }, } local map_load = { shift = 21, mask = 9, { shift = 20, mask = 5, [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL", }, _ = { shift = 20, mask = 5, [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL", } } local map_load1 = { shift = 4, mask = 1, [0] = map_load, map_media, } local map_loadm = { shift = 20, mask = 1, [0] = { shift = 23, mask = 3, [0] = "stmdaNR", "stmNR", { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR", }, { shift = 23, mask = 3, [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", }, "ldmdbNR", "ldmibNR", }, } local map_data = { shift = 21, mask = 15, [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs", "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs", "tstNP", "teqNP", "cmpNP", "cmnNP", "orrDNPs", "movDPs", "bicDNPs", "mvnDPs", } local map_mul = { shift = 21, mask = 7, [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS", "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs", } local map_sync = { shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd. [0] = "swpDMN", false, false, false, "swpbDMN", false, false, false, "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN", "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN", } local map_mulh = { shift = 21, mask = 3, [0] = { shift = 5, mask = 3, [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", }, { shift = 5, mask = 3, [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", }, { shift = 5, mask = 3, [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", }, { shift = 5, mask = 3, [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", }, } local map_misc = { shift = 4, mask = 7, -- NYI: decode PSR bits of msr. [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", }, { shift = 21, mask = 3, "bxM", false, "clzDM", }, { shift = 21, mask = 3, "bxjM", }, { shift = 21, mask = 3, "blxM", }, false, { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", }, false, { shift = 21, mask = 3, "bkptK", }, } local map_datar = { shift = 4, mask = 9, [9] = { shift = 5, mask = 3, [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, }, { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", }, { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", }, { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", }, }, _ = { shift = 20, mask = 25, [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, }, _ = { shift = 0, mask = 0xffffffff, [bor(0xe1a00000)] = "nop", _ = map_data, } }, } local map_datai = { shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12. [16] = "movwDW", [20] = "movtDW", [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", }, [22] = "msrNW", _ = map_data, } local map_branch = { shift = 24, mask = 1, [0] = "bB", "blB" } local map_condins = { [0] = map_datar, map_datai, map_load, map_load1, map_loadm, map_branch, map_loadc, map_datac } -- NYI: setend. local map_uncondins = { [0] = false, map_simddata, map_simdload, map_preload, false, "blxB", map_loadcu, map_datacu, } ------------------------------------------------------------------------------ local map_gpr = { [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", } local map_cond = { [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", } local map_shift = { [0] = "lsl", "lsr", "asr", "ror", } ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local pos = ctx.pos local extra = "" if ctx.rel then local sym = ctx.symtab[ctx.rel] if sym then extra = "\t->"..sym elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then extra = "\t; 0x"..tohex(ctx.rel) end end if ctx.hexdump > 0 then ctx.out(format("%08x %s %-5s %s%s\n", ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) else ctx.out(format("%08x %-5s %s%s\n", ctx.addr+pos, text, concat(operands, ", "), extra)) end ctx.pos = pos + 4 end -- Fallback for unknown opcodes. local function unknown(ctx) return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) end -- Format operand 2 of load/store opcodes. local function fmtload(ctx, op, pos) local base = map_gpr[band(rshift(op, 16), 15)] local x, ofs local ext = (band(op, 0x04000000) == 0) if not ext and band(op, 0x02000000) == 0 then ofs = band(op, 4095) if band(op, 0x00800000) == 0 then ofs = -ofs end if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end ofs = "#"..ofs elseif ext and band(op, 0x00400000) ~= 0 then ofs = band(op, 15) + band(rshift(op, 4), 0xf0) if band(op, 0x00800000) == 0 then ofs = -ofs end if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end ofs = "#"..ofs else ofs = map_gpr[band(op, 15)] if ext or band(op, 0xfe0) == 0 then elseif band(op, 0xfe0) == 0x60 then ofs = format("%s, rrx", ofs) else local sh = band(rshift(op, 7), 31) if sh == 0 then sh = 32 end ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh) end if band(op, 0x00800000) == 0 then ofs = "-"..ofs end end if ofs == "#0" then x = format("[%s]", base) elseif band(op, 0x01000000) == 0 then x = format("[%s], %s", base, ofs) else x = format("[%s, %s]", base, ofs) end if band(op, 0x01200000) == 0x01200000 then x = x.."!" end return x end -- Format operand 2 of vector load/store opcodes. local function fmtvload(ctx, op, pos) local base = map_gpr[band(rshift(op, 16), 15)] local ofs = band(op, 255)*4 if band(op, 0x00800000) == 0 then ofs = -ofs end if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end if ofs == 0 then return format("[%s]", base) else return format("[%s, #%d]", base, ofs) end end local function fmtvr(op, vr, sh0, sh1) if vr == "s" then return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1)) else return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16)) end end -- Disassemble a single instruction. local function disass_ins(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) local operands = {} local suffix = "" local last, name, pat local vr ctx.op = op ctx.rel = nil local cond = rshift(op, 28) local opat if cond == 15 then opat = map_uncondins[band(rshift(op, 25), 7)] else if cond ~= 14 then suffix = map_cond[cond] end opat = map_condins[band(rshift(op, 25), 7)] end while type(opat) ~= "string" do if not opat then return unknown(ctx) end opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ end name, pat = match(opat, "^([a-z0-9]*)(.*)") if sub(pat, 1, 1) == "." then local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") suffix = suffix..s2 pat = p2 end for p in gmatch(pat, ".") do local x = nil if p == "D" then x = map_gpr[band(rshift(op, 12), 15)] elseif p == "N" then x = map_gpr[band(rshift(op, 16), 15)] elseif p == "S" then x = map_gpr[band(rshift(op, 8), 15)] elseif p == "M" then x = map_gpr[band(op, 15)] elseif p == "d" then x = fmtvr(op, vr, 12, 22) elseif p == "n" then x = fmtvr(op, vr, 16, 7) elseif p == "m" then x = fmtvr(op, vr, 0, 5) elseif p == "P" then if band(op, 0x02000000) ~= 0 then x = ror(band(op, 255), 2*band(rshift(op, 8), 15)) else x = map_gpr[band(op, 15)] if band(op, 0xff0) ~= 0 then operands[#operands+1] = x local s = map_shift[band(rshift(op, 5), 3)] local r = nil if band(op, 0xf90) == 0 then if s == "ror" then s = "rrx" else r = "#32" end elseif band(op, 0x10) == 0 then r = "#"..band(rshift(op, 7), 31) else r = map_gpr[band(rshift(op, 8), 15)] end if name == "mov" then name = s; x = r elseif r then x = format("%s %s", s, r) else x = s end end end elseif p == "L" then x = fmtload(ctx, op, pos) elseif p == "l" then x = fmtvload(ctx, op, pos) elseif p == "B" then local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6) if cond == 15 then addr = addr + band(rshift(op, 23), 2) end ctx.rel = addr x = "0x"..tohex(addr) elseif p == "F" then vr = "s" elseif p == "G" then vr = "d" elseif p == "." then suffix = suffix..(vr == "s" and ".f32" or ".f64") elseif p == "R" then if band(op, 0x00200000) ~= 0 and #operands == 1 then operands[1] = operands[1].."!" end local t = {} for i=0,15 do if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end end x = "{"..concat(t, ", ").."}" elseif p == "r" then if band(op, 0x00200000) ~= 0 and #operands == 2 then operands[1] = operands[1].."!" end local s = tonumber(sub(last, 2)) local n = band(op, 255) if vr == "d" then n = rshift(n, 1) end operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1) elseif p == "W" then x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000) elseif p == "T" then x = "#0x"..tohex(band(op, 0x00ffffff), 6) elseif p == "U" then x = band(rshift(op, 7), 31) if x == 0 then x = nil end elseif p == "u" then x = band(rshift(op, 7), 31) if band(op, 0x40) == 0 then if x == 0 then x = nil else x = "lsl #"..x end else if x == 0 then x = "asr #32" else x = "asr #"..x end end elseif p == "v" then x = band(rshift(op, 7), 31) elseif p == "w" then x = band(rshift(op, 16), 31) elseif p == "x" then x = band(rshift(op, 16), 31) + 1 elseif p == "X" then x = band(rshift(op, 16), 31) - last + 1 elseif p == "Y" then x = band(rshift(op, 12), 0xf0) + band(op, 0x0f) elseif p == "K" then x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4) elseif p == "s" then if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end else assert(false) end if x then last = x if type(x) == "number" then x = "#"..x end operands[#operands+1] = x end end return putop(ctx, name..suffix, operands) end ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code ctx.pos = ofs ctx.rel = nil while ctx.pos < stop do disass_ins(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = addr or 0 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 8 return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 16 then return map_gpr[r] end return "d"..(r-16) end -- Public module functions. return { create = create, disass = disass, regname = regname }
| ver. 1.4 |
Github
|
.
| PHP 8.2.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings