dis_mips.lua (13228B)
1 ---------------------------------------------------------------------------- 2 -- LuaJIT MIPS disassembler module. 3 -- 4 -- Copyright (C) 2005-2016 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", "or|moveDST0", "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, "jalxJ", 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 return { 422 create = create, 423 create_el = create_el, 424 disass = disass, 425 disass_el = disass_el, 426 regname = regname 427 } 428