dis_arm.lua (19363B)
1 ---------------------------------------------------------------------------- 2 -- LuaJIT ARM disassembler module. 3 -- 4 -- Copyright (C) 2005-2016 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 return { 685 create = create, 686 disass = disass, 687 regname = regname 688 } 689