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