src/jit/dis_mips.lua - luajit-2.0-src

Functions defined

Source code

  1. ----------------------------------------------------------------------------
  2. -- LuaJIT MIPS disassembler module.
  3. --
  4. -- Copyright (C) 2005-2015 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 sub, byte, format = string.sub, string.byte, string.format
  14. local match, gmatch, gsub = string.match, string.gmatch, string.gsub
  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.   false,        false,                false,                false,
  34.   "multST",        "multuST",        "divST",        "divuST",
  35.   false,        false,                false,                false,
  36.   "addDST",        "addu|moveDST0", "subDST",        "subu|neguDS0T",
  37.   "andDST",        "orDST",        "xorDST",        "nor|notDST0",
  38.   false,        false,                "sltDST",        "sltuDST",
  39.   false,        false,                false,                false,
  40.   "tgeSTZ",        "tgeuSTZ",        "tltSTZ",        "tltuSTZ",
  41.   "teqSTZ",        false,                "tneSTZ",
  42. }

  43. local map_special2 = {
  44.   shift = 0, mask = 63,
  45.   [0] = "maddST", "madduST",        "mulDST",        false,
  46.   "msubST",        "msubuST",
  47.   [32] = "clzDS", [33] = "cloDS",
  48.   [63] = "sdbbpY",
  49. }

  50. local map_bshfl = {
  51.   shift = 6, mask = 31,
  52.   [2] = "wsbhDT",
  53.   [16] = "sebDT",
  54.   [24] = "sehDT",
  55. }

  56. local map_special3 = {
  57.   shift = 0, mask = 63,
  58.   [0] = "extTSAK", [4] = "insTSAL",
  59.   [32] = map_bshfl,
  60.   [59] = "rdhwrTD",
  61. }

  62. local map_regimm = {
  63.   shift = 16, mask = 31,
  64.   [0] = "bltzSB",        "bgezSB",        "bltzlSB",        "bgezlSB",
  65.   false,        false,                false,                false,
  66.   "tgeiSI",        "tgeiuSI",        "tltiSI",        "tltiuSI",
  67.   "teqiSI",        false,                "tneiSI",        false,
  68.   "bltzalSB",        "bgezalSB",        "bltzallSB",        "bgezallSB",
  69.   false,        false,                false,                false,
  70.   false,        false,                false,                false,
  71.   false,        false,                false,                "synciSO",
  72. }

  73. local map_cop0 = {
  74.   shift = 25, mask = 1,
  75.   [0] = {
  76.     shift = 21, mask = 15,
  77.     [0] = "mfc0TDW", [4] = "mtc0TDW",
  78.     [10] = "rdpgprDT",
  79.     [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
  80.     [14] = "wrpgprDT",
  81.   }, {
  82.     shift = 0, mask = 63,
  83.     [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
  84.     [24] = "eret", [31] = "deret",
  85.     [32] = "wait",
  86.   },
  87. }

  88. local map_cop1s = {
  89.   shift = 0, mask = 63,
  90.   [0] = "add.sFGH",        "sub.sFGH",        "mul.sFGH",        "div.sFGH",
  91.   "sqrt.sFG",                "abs.sFG",        "mov.sFG",        "neg.sFG",
  92.   "round.l.sFG",        "trunc.l.sFG",        "ceil.l.sFG",        "floor.l.sFG",
  93.   "round.w.sFG",        "trunc.w.sFG",        "ceil.w.sFG",        "floor.w.sFG",
  94.   false,
  95.   { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
  96.   "movz.sFGT",        "movn.sFGT",
  97.   false,        "recip.sFG",        "rsqrt.sFG",        false,
  98.   false,        false,                false,                false,
  99.   false,        false,                false,                false,
  100.   false,        "cvt.d.sFG",        false,                false,
  101.   "cvt.w.sFG",        "cvt.l.sFG",        "cvt.ps.sFGH",        false,
  102.   false,        false,                false,                false,
  103.   false,        false,                false,                false,
  104.   "c.f.sVGH",        "c.un.sVGH",        "c.eq.sVGH",        "c.ueq.sVGH",
  105.   "c.olt.sVGH",        "c.ult.sVGH",        "c.ole.sVGH",        "c.ule.sVGH",
  106.   "c.sf.sVGH",        "c.ngle.sVGH",        "c.seq.sVGH",        "c.ngl.sVGH",
  107.   "c.lt.sVGH",        "c.nge.sVGH",        "c.le.sVGH",        "c.ngt.sVGH",
  108. }

  109. local map_cop1d = {
  110.   shift = 0, mask = 63,
  111.   [0] = "add.dFGH",        "sub.dFGH",        "mul.dFGH",        "div.dFGH",
  112.   "sqrt.dFG",                "abs.dFG",        "mov.dFG",        "neg.dFG",
  113.   "round.l.dFG",        "trunc.l.dFG",        "ceil.l.dFG",        "floor.l.dFG",
  114.   "round.w.dFG",        "trunc.w.dFG",        "ceil.w.dFG",        "floor.w.dFG",
  115.   false,
  116.   { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
  117.   "movz.dFGT",        "movn.dFGT",
  118.   false,        "recip.dFG",        "rsqrt.dFG",        false,
  119.   false,        false,                false,                false,
  120.   false,        false,                false,                false,
  121.   "cvt.s.dFG",        false,                false,                false,
  122.   "cvt.w.dFG",        "cvt.l.dFG",        false,                false,
  123.   false,        false,                false,                false,
  124.   false,        false,                false,                false,
  125.   "c.f.dVGH",        "c.un.dVGH",        "c.eq.dVGH",        "c.ueq.dVGH",
  126.   "c.olt.dVGH",        "c.ult.dVGH",        "c.ole.dVGH",        "c.ule.dVGH",
  127.   "c.df.dVGH",        "c.ngle.dVGH",        "c.deq.dVGH",        "c.ngl.dVGH",
  128.   "c.lt.dVGH",        "c.nge.dVGH",        "c.le.dVGH",        "c.ngt.dVGH",
  129. }

  130. local map_cop1ps = {
  131.   shift = 0, mask = 63,
  132.   [0] = "add.psFGH",        "sub.psFGH",        "mul.psFGH",        false,
  133.   false,                "abs.psFG",        "mov.psFG",        "neg.psFG",
  134.   false,                false,                false,                false,
  135.   false,                false,                false,                false,
  136.   false,
  137.   { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
  138.   "movz.psFGT",        "movn.psFGT",
  139.   false,        false,                false,                false,
  140.   false,        false,                false,                false,
  141.   false,        false,                false,                false,
  142.   "cvt.s.puFG",        false,                false,                false,
  143.   false,        false,                false,                false,
  144.   "cvt.s.plFG",        false,                false,                false,
  145.   "pll.psFGH",        "plu.psFGH",        "pul.psFGH",        "puu.psFGH",
  146.   "c.f.psVGH",        "c.un.psVGH",        "c.eq.psVGH",        "c.ueq.psVGH",
  147.   "c.olt.psVGH", "c.ult.psVGH",        "c.ole.psVGH",        "c.ule.psVGH",
  148.   "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
  149.   "c.lt.psVGH",        "c.nge.psVGH",        "c.le.psVGH",        "c.ngt.psVGH",
  150. }

  151. local map_cop1w = {
  152.   shift = 0, mask = 63,
  153.   [32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
  154. }

  155. local map_cop1l = {
  156.   shift = 0, mask = 63,
  157.   [32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
  158. }

  159. local map_cop1bc = {
  160.   shift = 16, mask = 3,
  161.   [0] = "bc1fCB", "bc1tCB",        "bc1flCB",        "bc1tlCB",
  162. }

  163. local map_cop1 = {
  164.   shift = 21, mask = 31,
  165.   [0] = "mfc1TG", false,        "cfc1TG",        "mfhc1TG",
  166.   "mtc1TG",        false,                "ctc1TG",        "mthc1TG",
  167.   map_cop1bc,        false,                false,                false,
  168.   false,        false,                false,                false,
  169.   map_cop1s,        map_cop1d,        false,                false,
  170.   map_cop1w,        map_cop1l,        map_cop1ps,
  171. }

  172. local map_cop1x = {
  173.   shift = 0, mask = 63,
  174.   [0] = "lwxc1FSX",        "ldxc1FSX",        false,                false,
  175.   false,        "luxc1FSX",        false,                false,
  176.   "swxc1FSX",        "sdxc1FSX",        false,                false,
  177.   false,        "suxc1FSX",        false,                "prefxMSX",
  178.   false,        false,                false,                false,
  179.   false,        false,                false,                false,
  180.   false,        false,                false,                false,
  181.   false,        false,                "alnv.psFGHS",        false,
  182.   "madd.sFRGH",        "madd.dFRGH",        false,                false,
  183.   false,        false,                "madd.psFRGH",        false,
  184.   "msub.sFRGH",        "msub.dFRGH",        false,                false,
  185.   false,        false,                "msub.psFRGH",        false,
  186.   "nmadd.sFRGH", "nmadd.dFRGH",        false,                false,
  187.   false,        false,                "nmadd.psFRGH",        false,
  188.   "nmsub.sFRGH", "nmsub.dFRGH",        false,                false,
  189.   false,        false,                "nmsub.psFRGH",        false,
  190. }

  191. local map_pri = {
  192.   [0] = map_special,        map_regimm,        "jJ",        "jalJ",
  193.   "beq|beqz|bST00B",        "bne|bnezST0B",                "blezSB",        "bgtzSB",
  194.   "addiTSI",        "addiu|liTS0I",        "sltiTSI",        "sltiuTSI",
  195.   "andiTSU",        "ori|liTS0U",        "xoriTSU",        "luiTU",
  196.   map_cop0,        map_cop1,        false,                map_cop1x,
  197.   "beql|beqzlST0B",        "bnel|bnezlST0B",        "blezlSB",        "bgtzlSB",
  198.   false,        false,                false,                false,
  199.   map_special2,        false,                false,                map_special3,
  200.   "lbTSO",        "lhTSO",        "lwlTSO",        "lwTSO",
  201.   "lbuTSO",        "lhuTSO",        "lwrTSO",        false,
  202.   "sbTSO",        "shTSO",        "swlTSO",        "swTSO",
  203.   false,        false,                "swrTSO",        "cacheNSO",
  204.   "llTSO",        "lwc1HSO",        "lwc2TSO",        "prefNSO",
  205.   false,        "ldc1HSO",        "ldc2TSO",        false,
  206.   "scTSO",        "swc1HSO",        "swc2TSO",        false,
  207.   false,        "sdc1HSO",        "sdc2TSO",        false,
  208. }

  209. ------------------------------------------------------------------------------

  210. local map_gpr = {
  211.   [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  212.   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
  213.   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
  214.   "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
  215. }

  216. ------------------------------------------------------------------------------

  217. -- Output a nicely formatted line with an opcode and operands.
  218. local function putop(ctx, text, operands)
  219.   local pos = ctx.pos
  220.   local extra = ""
  221.   if ctx.rel then
  222.     local sym = ctx.symtab[ctx.rel]
  223.     if sym then extra = "\t->"..sym end
  224.   end
  225.   if ctx.hexdump > 0 then
  226.     ctx.out(format("%08x  %s  %-7s %s%s\n",
  227.             ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
  228.   else
  229.     ctx.out(format("%08x  %-7s %s%s\n",
  230.             ctx.addr+pos, text, concat(operands, ", "), extra))
  231.   end
  232.   ctx.pos = pos + 4
  233. end

  234. -- Fallback for unknown opcodes.
  235. local function unknown(ctx)
  236.   return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
  237. end

  238. local function get_be(ctx)
  239.   local pos = ctx.pos
  240.   local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  241.   return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
  242. end

  243. local function get_le(ctx)
  244.   local pos = ctx.pos
  245.   local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  246.   return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
  247. end

  248. -- Disassemble a single instruction.
  249. local function disass_ins(ctx)
  250.   local op = ctx:get()
  251.   local operands = {}
  252.   local last = nil
  253.   ctx.op = op
  254.   ctx.rel = nil

  255.   local opat = map_pri[rshift(op, 26)]
  256.   while type(opat) ~= "string" do
  257.     if not opat then return unknown(ctx) end
  258.     opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
  259.   end
  260.   local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
  261.   local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
  262.   if altname then pat = pat2 end

  263.   for p in gmatch(pat, ".") do
  264.     local x = nil
  265.     if p == "S" then
  266.       x = map_gpr[band(rshift(op, 21), 31)]
  267.     elseif p == "T" then
  268.       x = map_gpr[band(rshift(op, 16), 31)]
  269.     elseif p == "D" then
  270.       x = map_gpr[band(rshift(op, 11), 31)]
  271.     elseif p == "F" then
  272.       x = "f"..band(rshift(op, 6), 31)
  273.     elseif p == "G" then
  274.       x = "f"..band(rshift(op, 11), 31)
  275.     elseif p == "H" then
  276.       x = "f"..band(rshift(op, 16), 31)
  277.     elseif p == "R" then
  278.       x = "f"..band(rshift(op, 21), 31)
  279.     elseif p == "A" then
  280.       x = band(rshift(op, 6), 31)
  281.     elseif p == "M" then
  282.       x = band(rshift(op, 11), 31)
  283.     elseif p == "N" then
  284.       x = band(rshift(op, 16), 31)
  285.     elseif p == "C" then
  286.       x = band(rshift(op, 18), 7)
  287.       if x == 0 then x = nil end
  288.     elseif p == "K" then
  289.       x = band(rshift(op, 11), 31) + 1
  290.     elseif p == "L" then
  291.       x = band(rshift(op, 11), 31) - last + 1
  292.     elseif p == "I" then
  293.       x = arshift(lshift(op, 16), 16)
  294.     elseif p == "U" then
  295.       x = band(op, 0xffff)
  296.     elseif p == "O" then
  297.       local disp = arshift(lshift(op, 16), 16)
  298.       operands[#operands] = format("%d(%s)", disp, last)
  299.     elseif p == "X" then
  300.       local index = map_gpr[band(rshift(op, 16), 31)]
  301.       operands[#operands] = format("%s(%s)", index, last)
  302.     elseif p == "B" then
  303.       x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4
  304.       ctx.rel = x
  305.       x = "0x"..tohex(x)
  306.     elseif p == "J" then
  307.       x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4
  308.       ctx.rel = x
  309.       x = "0x"..tohex(x)
  310.     elseif p == "V" then
  311.       x = band(rshift(op, 8), 7)
  312.       if x == 0 then x = nil end
  313.     elseif p == "W" then
  314.       x = band(op, 7)
  315.       if x == 0 then x = nil end
  316.     elseif p == "Y" then
  317.       x = band(rshift(op, 6), 0x000fffff)
  318.       if x == 0 then x = nil end
  319.     elseif p == "Z" then
  320.       x = band(rshift(op, 6), 1023)
  321.       if x == 0 then x = nil end
  322.     elseif p == "0" then
  323.       if last == "r0" or last == 0 then
  324.         local n = #operands
  325.         operands[n] = nil
  326.         last = operands[n-1]
  327.         if altname then
  328.           local a1, a2 = match(altname, "([^|]*)|(.*)")
  329.           if a1 then name, altname = a1, a2
  330.           else name = altname end
  331.         end
  332.       end
  333.     elseif p == "1" then
  334.       if last == "ra" then
  335.         operands[#operands] = nil
  336.       end
  337.     else
  338.       assert(false)
  339.     end
  340.     if x then operands[#operands+1] = x; last = x end
  341.   end

  342.   return putop(ctx, name, operands)
  343. end

  344. ------------------------------------------------------------------------------

  345. -- Disassemble a block of code.
  346. local function disass_block(ctx, ofs, len)
  347.   if not ofs then ofs = 0 end
  348.   local stop = len and ofs+len or #ctx.code
  349.   stop = stop - stop % 4
  350.   ctx.pos = ofs - ofs % 4
  351.   ctx.rel = nil
  352.   while ctx.pos < stop do disass_ins(ctx) end
  353. end

  354. -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
  355. local function create(code, addr, out)
  356.   local ctx = {}
  357.   ctx.code = code
  358.   ctx.addr = addr or 0
  359.   ctx.out = out or io.write
  360.   ctx.symtab = {}
  361.   ctx.disass = disass_block
  362.   ctx.hexdump = 8
  363.   ctx.get = get_be
  364.   return ctx
  365. end

  366. local function create_el(code, addr, out)
  367.   local ctx = create(code, addr, out)
  368.   ctx.get = get_le
  369.   return ctx
  370. end

  371. -- Simple API: disassemble code (a string) at address and output via out.
  372. local function disass(code, addr, out)
  373.   create(code, addr, out):disass()
  374. end

  375. local function disass_el(code, addr, out)
  376.   create_el(code, addr, out):disass()
  377. end

  378. -- Return register name for RID.
  379. local function regname(r)
  380.   if r < 32 then return map_gpr[r] end
  381.   return "f"..(r-32)
  382. end

  383. -- Public module functions.
  384. return {
  385.   create = create,
  386.   create_el = create_el,
  387.   disass = disass,
  388.   disass_el = disass_el,
  389.   regname = regname
  390. }