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