dis_mips.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. ----------------------------------------------------------------------------
  2. -- LuaJIT MIPS disassembler module.
  3. --
  4. -- Copyright (C) 2005-2017 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. local type = type
  13. local byte, format = string.byte, string.format
  14. local match, gmatch = string.match, string.gmatch
  15. local concat = table.concat
  16. local bit = require("bit")
  17. local band, bor, tohex = bit.band, bit.bor, bit.tohex
  18. local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
  19. ------------------------------------------------------------------------------
  20. -- Primary and extended opcode maps
  21. ------------------------------------------------------------------------------
  22. local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
  23. local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
  24. local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
  25. local map_special = {
  26. shift = 0, mask = 63,
  27. [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
  28. map_movci, map_srl, "sraDTA",
  29. "sllvDTS", false, map_srlv, "sravDTS",
  30. "jrS", "jalrD1S", "movzDST", "movnDST",
  31. "syscallY", "breakY", false, "sync",
  32. "mfhiD", "mthiS", "mfloD", "mtloS",
  33. "dsllvDST", false, "dsrlvDST", "dsravDST",
  34. "multST", "multuST", "divST", "divuST",
  35. "dmultST", "dmultuST", "ddivST", "ddivuST",
  36. "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
  37. "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
  38. false, false, "sltDST", "sltuDST",
  39. "daddDST", "dadduDST", "dsubDST", "dsubuDST",
  40. "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
  41. "teqSTZ", false, "tneSTZ", false,
  42. "dsllDTA", false, "dsrlDTA", "dsraDTA",
  43. "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
  44. }
  45. local map_special2 = {
  46. shift = 0, mask = 63,
  47. [0] = "maddST", "madduST", "mulDST", false,
  48. "msubST", "msubuST",
  49. [32] = "clzDS", [33] = "cloDS",
  50. [63] = "sdbbpY",
  51. }
  52. local map_bshfl = {
  53. shift = 6, mask = 31,
  54. [2] = "wsbhDT",
  55. [16] = "sebDT",
  56. [24] = "sehDT",
  57. }
  58. local map_dbshfl = {
  59. shift = 6, mask = 31,
  60. [2] = "dsbhDT",
  61. [5] = "dshdDT",
  62. }
  63. local map_special3 = {
  64. shift = 0, mask = 63,
  65. [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
  66. [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
  67. [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
  68. }
  69. local map_regimm = {
  70. shift = 16, mask = 31,
  71. [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
  72. false, false, false, false,
  73. "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
  74. "teqiSI", false, "tneiSI", false,
  75. "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
  76. false, false, false, false,
  77. false, false, false, false,
  78. false, false, false, "synciSO",
  79. }
  80. local map_cop0 = {
  81. shift = 25, mask = 1,
  82. [0] = {
  83. shift = 21, mask = 15,
  84. [0] = "mfc0TDW", [4] = "mtc0TDW",
  85. [10] = "rdpgprDT",
  86. [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
  87. [14] = "wrpgprDT",
  88. }, {
  89. shift = 0, mask = 63,
  90. [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
  91. [24] = "eret", [31] = "deret",
  92. [32] = "wait",
  93. },
  94. }
  95. local map_cop1s = {
  96. shift = 0, mask = 63,
  97. [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
  98. "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
  99. "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
  100. "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
  101. false,
  102. { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
  103. "movz.sFGT", "movn.sFGT",
  104. false, "recip.sFG", "rsqrt.sFG", false,
  105. false, false, false, false,
  106. false, false, false, false,
  107. false, "cvt.d.sFG", false, false,
  108. "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
  109. false, false, false, false,
  110. false, false, false, false,
  111. "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
  112. "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
  113. "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
  114. "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
  115. }
  116. local map_cop1d = {
  117. shift = 0, mask = 63,
  118. [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
  119. "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
  120. "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
  121. "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
  122. false,
  123. { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
  124. "movz.dFGT", "movn.dFGT",
  125. false, "recip.dFG", "rsqrt.dFG", false,
  126. false, false, false, false,
  127. false, false, false, false,
  128. "cvt.s.dFG", false, false, false,
  129. "cvt.w.dFG", "cvt.l.dFG", false, false,
  130. false, false, false, false,
  131. false, false, false, false,
  132. "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
  133. "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
  134. "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
  135. "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
  136. }
  137. local map_cop1ps = {
  138. shift = 0, mask = 63,
  139. [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
  140. false, "abs.psFG", "mov.psFG", "neg.psFG",
  141. false, false, false, false,
  142. false, false, false, false,
  143. false,
  144. { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
  145. "movz.psFGT", "movn.psFGT",
  146. false, false, false, false,
  147. false, false, false, false,
  148. false, false, false, false,
  149. "cvt.s.puFG", false, false, false,
  150. false, false, false, false,
  151. "cvt.s.plFG", false, false, false,
  152. "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
  153. "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
  154. "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
  155. "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
  156. "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
  157. }
  158. local map_cop1w = {
  159. shift = 0, mask = 63,
  160. [32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
  161. }
  162. local map_cop1l = {
  163. shift = 0, mask = 63,
  164. [32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
  165. }
  166. local map_cop1bc = {
  167. shift = 16, mask = 3,
  168. [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
  169. }
  170. local map_cop1 = {
  171. shift = 21, mask = 31,
  172. [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
  173. "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
  174. map_cop1bc, false, false, false,
  175. false, false, false, false,
  176. map_cop1s, map_cop1d, false, false,
  177. map_cop1w, map_cop1l, map_cop1ps,
  178. }
  179. local map_cop1x = {
  180. shift = 0, mask = 63,
  181. [0] = "lwxc1FSX", "ldxc1FSX", false, false,
  182. false, "luxc1FSX", false, false,
  183. "swxc1FSX", "sdxc1FSX", false, false,
  184. false, "suxc1FSX", false, "prefxMSX",
  185. false, false, false, false,
  186. false, false, false, false,
  187. false, false, false, false,
  188. false, false, "alnv.psFGHS", false,
  189. "madd.sFRGH", "madd.dFRGH", false, false,
  190. false, false, "madd.psFRGH", false,
  191. "msub.sFRGH", "msub.dFRGH", false, false,
  192. false, false, "msub.psFRGH", false,
  193. "nmadd.sFRGH", "nmadd.dFRGH", false, false,
  194. false, false, "nmadd.psFRGH", false,
  195. "nmsub.sFRGH", "nmsub.dFRGH", false, false,
  196. false, false, "nmsub.psFRGH", false,
  197. }
  198. local map_pri = {
  199. [0] = map_special, map_regimm, "jJ", "jalJ",
  200. "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
  201. "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
  202. "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
  203. map_cop0, map_cop1, false, map_cop1x,
  204. "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
  205. "daddiTSI", "daddiuTSI", false, false,
  206. map_special2, "jalxJ", false, map_special3,
  207. "lbTSO", "lhTSO", "lwlTSO", "lwTSO",
  208. "lbuTSO", "lhuTSO", "lwrTSO", false,
  209. "sbTSO", "shTSO", "swlTSO", "swTSO",
  210. false, false, "swrTSO", "cacheNSO",
  211. "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
  212. false, "ldc1HSO", "ldc2TSO", "ldTSO",
  213. "scTSO", "swc1HSO", "swc2TSO", false,
  214. false, "sdc1HSO", "sdc2TSO", "sdTSO",
  215. }
  216. ------------------------------------------------------------------------------
  217. local map_gpr = {
  218. [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  219. "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
  220. "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
  221. "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
  222. }
  223. ------------------------------------------------------------------------------
  224. -- Output a nicely formatted line with an opcode and operands.
  225. local function putop(ctx, text, operands)
  226. local pos = ctx.pos
  227. local extra = ""
  228. if ctx.rel then
  229. local sym = ctx.symtab[ctx.rel]
  230. if sym then extra = "\t->"..sym end
  231. end
  232. if ctx.hexdump > 0 then
  233. ctx.out(format("%08x %s %-7s %s%s\n",
  234. ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
  235. else
  236. ctx.out(format("%08x %-7s %s%s\n",
  237. ctx.addr+pos, text, concat(operands, ", "), extra))
  238. end
  239. ctx.pos = pos + 4
  240. end
  241. -- Fallback for unknown opcodes.
  242. local function unknown(ctx)
  243. return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
  244. end
  245. local function get_be(ctx)
  246. local pos = ctx.pos
  247. local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  248. return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
  249. end
  250. local function get_le(ctx)
  251. local pos = ctx.pos
  252. local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  253. return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
  254. end
  255. -- Disassemble a single instruction.
  256. local function disass_ins(ctx)
  257. local op = ctx:get()
  258. local operands = {}
  259. local last = nil
  260. ctx.op = op
  261. ctx.rel = nil
  262. local opat = map_pri[rshift(op, 26)]
  263. while type(opat) ~= "string" do
  264. if not opat then return unknown(ctx) end
  265. opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
  266. end
  267. local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
  268. local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
  269. if altname then pat = pat2 end
  270. for p in gmatch(pat, ".") do
  271. local x = nil
  272. if p == "S" then
  273. x = map_gpr[band(rshift(op, 21), 31)]
  274. elseif p == "T" then
  275. x = map_gpr[band(rshift(op, 16), 31)]
  276. elseif p == "D" then
  277. x = map_gpr[band(rshift(op, 11), 31)]
  278. elseif p == "F" then
  279. x = "f"..band(rshift(op, 6), 31)
  280. elseif p == "G" then
  281. x = "f"..band(rshift(op, 11), 31)
  282. elseif p == "H" then
  283. x = "f"..band(rshift(op, 16), 31)
  284. elseif p == "R" then
  285. x = "f"..band(rshift(op, 21), 31)
  286. elseif p == "A" then
  287. x = band(rshift(op, 6), 31)
  288. elseif p == "E" then
  289. x = band(rshift(op, 6), 31) + 32
  290. elseif p == "M" then
  291. x = band(rshift(op, 11), 31)
  292. elseif p == "N" then
  293. x = band(rshift(op, 16), 31)
  294. elseif p == "C" then
  295. x = band(rshift(op, 18), 7)
  296. if x == 0 then x = nil end
  297. elseif p == "K" then
  298. x = band(rshift(op, 11), 31) + 1
  299. elseif p == "P" then
  300. x = band(rshift(op, 11), 31) + 33
  301. elseif p == "L" then
  302. x = band(rshift(op, 11), 31) - last + 1
  303. elseif p == "Q" then
  304. x = band(rshift(op, 11), 31) - last + 33
  305. elseif p == "I" then
  306. x = arshift(lshift(op, 16), 16)
  307. elseif p == "U" then
  308. x = band(op, 0xffff)
  309. elseif p == "O" then
  310. local disp = arshift(lshift(op, 16), 16)
  311. operands[#operands] = format("%d(%s)", disp, last)
  312. elseif p == "X" then
  313. local index = map_gpr[band(rshift(op, 16), 31)]
  314. operands[#operands] = format("%s(%s)", index, last)
  315. elseif p == "B" then
  316. x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4
  317. ctx.rel = x
  318. x = format("0x%08x", x)
  319. elseif p == "J" then
  320. local a = ctx.addr + ctx.pos
  321. x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
  322. ctx.rel = x
  323. x = format("0x%08x", x)
  324. elseif p == "V" then
  325. x = band(rshift(op, 8), 7)
  326. if x == 0 then x = nil end
  327. elseif p == "W" then
  328. x = band(op, 7)
  329. if x == 0 then x = nil end
  330. elseif p == "Y" then
  331. x = band(rshift(op, 6), 0x000fffff)
  332. if x == 0 then x = nil end
  333. elseif p == "Z" then
  334. x = band(rshift(op, 6), 1023)
  335. if x == 0 then x = nil end
  336. elseif p == "0" then
  337. if last == "r0" or last == 0 then
  338. local n = #operands
  339. operands[n] = nil
  340. last = operands[n-1]
  341. if altname then
  342. local a1, a2 = match(altname, "([^|]*)|(.*)")
  343. if a1 then name, altname = a1, a2
  344. else name = altname end
  345. end
  346. end
  347. elseif p == "1" then
  348. if last == "ra" then
  349. operands[#operands] = nil
  350. end
  351. else
  352. assert(false)
  353. end
  354. if x then operands[#operands+1] = x; last = x end
  355. end
  356. return putop(ctx, name, operands)
  357. end
  358. ------------------------------------------------------------------------------
  359. -- Disassemble a block of code.
  360. local function disass_block(ctx, ofs, len)
  361. if not ofs then ofs = 0 end
  362. local stop = len and ofs+len or #ctx.code
  363. stop = stop - stop % 4
  364. ctx.pos = ofs - ofs % 4
  365. ctx.rel = nil
  366. while ctx.pos < stop do disass_ins(ctx) end
  367. end
  368. -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
  369. local function create(code, addr, out)
  370. local ctx = {}
  371. ctx.code = code
  372. ctx.addr = addr or 0
  373. ctx.out = out or io.write
  374. ctx.symtab = {}
  375. ctx.disass = disass_block
  376. ctx.hexdump = 8
  377. ctx.get = get_be
  378. return ctx
  379. end
  380. local function create_el(code, addr, out)
  381. local ctx = create(code, addr, out)
  382. ctx.get = get_le
  383. return ctx
  384. end
  385. -- Simple API: disassemble code (a string) at address and output via out.
  386. local function disass(code, addr, out)
  387. create(code, addr, out):disass()
  388. end
  389. local function disass_el(code, addr, out)
  390. create_el(code, addr, out):disass()
  391. end
  392. -- Return register name for RID.
  393. local function regname(r)
  394. if r < 32 then return map_gpr[r] end
  395. return "f"..(r-32)
  396. end
  397. -- Public module functions.
  398. return {
  399. create = create,
  400. create_el = create_el,
  401. disass = disass,
  402. disass_el = disass_el,
  403. regname = regname
  404. }