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