dis_arm.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. ----------------------------------------------------------------------------
  2. -- LuaJIT ARM disassembler module.
  3. --
  4. -- Copyright (C) 2005-2010 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 most user-mode ARMv7 instructions
  10. -- NYI: Advanced SIMD and VFP instructions.
  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, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
  18. local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
  19. ------------------------------------------------------------------------------
  20. -- Opcode maps
  21. ------------------------------------------------------------------------------
  22. local map_loadc = {
  23. shift = 9, mask = 7,
  24. [5] = {
  25. shift = 0, mask = 0 -- NYI VFP load/store.
  26. },
  27. _ = {
  28. shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
  29. },
  30. }
  31. local map_datac = {
  32. shift = 24, mask = 1,
  33. [0] = {
  34. shift = 9, mask = 7,
  35. [5] = {
  36. shift = 0, mask = 0 -- NYI VFP data.
  37. },
  38. _ = {
  39. shift = 0, mask = 0 -- NYI cdp, mcr, mrc.
  40. },
  41. },
  42. "svcT",
  43. }
  44. local map_loadcu = {
  45. shift = 0, mask = 0, -- NYI unconditional CP load/store.
  46. }
  47. local map_datacu = {
  48. shift = 0, mask = 0, -- NYI unconditional CP data.
  49. }
  50. local map_simddata = {
  51. shift = 0, mask = 0, -- NYI SIMD data.
  52. }
  53. local map_simdload = {
  54. shift = 0, mask = 0, -- NYI SIMD load/store, preload.
  55. }
  56. local map_preload = {
  57. shift = 0, mask = 0, -- NYI preload.
  58. }
  59. local map_media = {
  60. shift = 20, mask = 31,
  61. [0] = false,
  62. { --01
  63. shift = 5, mask = 7,
  64. [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
  65. "sadd8DNM", false, false, "ssub8DNM",
  66. },
  67. { --02
  68. shift = 5, mask = 7,
  69. [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
  70. "qadd8DNM", false, false, "qsub8DNM",
  71. },
  72. { --03
  73. shift = 5, mask = 7,
  74. [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
  75. "shadd8DNM", false, false, "shsub8DNM",
  76. },
  77. false,
  78. { --05
  79. shift = 5, mask = 7,
  80. [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
  81. "uadd8DNM", false, false, "usub8DNM",
  82. },
  83. { --06
  84. shift = 5, mask = 7,
  85. [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
  86. "uqadd8DNM", false, false, "uqsub8DNM",
  87. },
  88. { --07
  89. shift = 5, mask = 7,
  90. [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
  91. "uhadd8DNM", false, false, "uhsub8DNM",
  92. },
  93. { --08
  94. shift = 5, mask = 7,
  95. [0] = "pkhbtDNMU", false, "pkhtbDNMU",
  96. { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
  97. "pkhbtDNMU", "selDNM", "pkhtbDNMU",
  98. },
  99. false,
  100. { --0a
  101. shift = 5, mask = 7,
  102. [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
  103. { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
  104. "ssatDxMu", false, "ssatDxMu",
  105. },
  106. { --0b
  107. shift = 5, mask = 7,
  108. [0] = "ssatDxMu", "revDM", "ssatDxMu",
  109. { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
  110. "ssatDxMu", "rev16DM", "ssatDxMu",
  111. },
  112. { --0c
  113. shift = 5, mask = 7,
  114. [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
  115. },
  116. false,
  117. { --0e
  118. shift = 5, mask = 7,
  119. [0] = "usatDwMu", "usat16DwM", "usatDwMu",
  120. { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
  121. "usatDwMu", false, "usatDwMu",
  122. },
  123. { --0f
  124. shift = 5, mask = 7,
  125. [0] = "usatDwMu", "rbitDM", "usatDwMu",
  126. { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
  127. "usatDwMu", "revshDM", "usatDwMu",
  128. },
  129. { --10
  130. shift = 12, mask = 15,
  131. [15] = {
  132. shift = 5, mask = 7,
  133. "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
  134. },
  135. _ = {
  136. shift = 5, mask = 7,
  137. [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
  138. },
  139. },
  140. false, false, false,
  141. { --14
  142. shift = 5, mask = 7,
  143. [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
  144. },
  145. { --15
  146. shift = 5, mask = 7,
  147. [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
  148. { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
  149. false, false, false, false,
  150. "smmlsNMSD", "smmlsrNMSD",
  151. },
  152. false, false,
  153. { --18
  154. shift = 5, mask = 7,
  155. [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
  156. },
  157. false,
  158. { --1a
  159. shift = 5, mask = 3, [2] = "sbfxDMvw",
  160. },
  161. { --1b
  162. shift = 5, mask = 3, [2] = "sbfxDMvw",
  163. },
  164. { --1c
  165. shift = 5, mask = 3,
  166. [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
  167. },
  168. { --1d
  169. shift = 5, mask = 3,
  170. [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
  171. },
  172. { --1e
  173. shift = 5, mask = 3, [2] = "ubfxDMvw",
  174. },
  175. { --1f
  176. shift = 5, mask = 3, [2] = "ubfxDMvw",
  177. },
  178. }
  179. local map_load = {
  180. shift = 21, mask = 9,
  181. {
  182. shift = 20, mask = 5,
  183. [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
  184. },
  185. _ = {
  186. shift = 20, mask = 5,
  187. [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
  188. }
  189. }
  190. local map_load1 = {
  191. shift = 4, mask = 1,
  192. [0] = map_load, map_media,
  193. }
  194. local map_loadm = {
  195. shift = 20, mask = 1,
  196. [0] = {
  197. shift = 23, mask = 3,
  198. [0] = "stmdaNR", "stmNR",
  199. { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
  200. },
  201. {
  202. shift = 23, mask = 3,
  203. [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
  204. "ldmdbNR", "ldmibNR",
  205. },
  206. }
  207. local map_data = {
  208. shift = 21, mask = 15,
  209. [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
  210. "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
  211. "tstNP", "teqNP", "cmpNP", "cmnNP",
  212. "orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
  213. }
  214. local map_mul = {
  215. shift = 21, mask = 7,
  216. [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
  217. "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
  218. }
  219. local map_sync = {
  220. shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
  221. [0] = "swpDMN", false, false, false,
  222. "swpbDMN", false, false, false,
  223. "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
  224. "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
  225. }
  226. local map_mulh = {
  227. shift = 21, mask = 3,
  228. [0] = { shift = 5, mask = 3,
  229. [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
  230. { shift = 5, mask = 3,
  231. [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
  232. { shift = 5, mask = 3,
  233. [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
  234. { shift = 5, mask = 3,
  235. [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
  236. }
  237. local map_misc = {
  238. shift = 4, mask = 7,
  239. -- NYI: decode PSR bits of msr.
  240. [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
  241. { shift = 21, mask = 3, "bxM", false, "clzDM", },
  242. { shift = 21, mask = 3, "bxjM", },
  243. { shift = 21, mask = 3, "blxM", },
  244. false,
  245. { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
  246. false,
  247. { shift = 21, mask = 3, "bkptK", },
  248. }
  249. local map_datar = {
  250. shift = 4, mask = 9,
  251. [9] = {
  252. shift = 5, mask = 3,
  253. [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
  254. { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
  255. { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
  256. { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
  257. },
  258. _ = {
  259. shift = 20, mask = 25,
  260. [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
  261. _ = {
  262. shift = 0, mask = 0xffffffff,
  263. [bor(0xe1a00000)] = "nop",
  264. _ = map_data,
  265. }
  266. },
  267. }
  268. local map_datai = {
  269. shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
  270. [16] = "movwDW", [20] = "movtDW",
  271. [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
  272. [22] = "msrNW",
  273. _ = map_data,
  274. }
  275. local map_branch = {
  276. shift = 24, mask = 1,
  277. [0] = "bB", "blB"
  278. }
  279. local map_condins = {
  280. [0] = map_datar, map_datai, map_load, map_load1,
  281. map_loadm, map_branch, map_loadc, map_datac
  282. }
  283. -- NYI: setend.
  284. local map_uncondins = {
  285. [0] = false, map_simddata, map_simdload, map_preload,
  286. false, "blxB", map_loadcu, map_datacu,
  287. }
  288. ------------------------------------------------------------------------------
  289. local map_gpr = {
  290. [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  291. "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
  292. }
  293. local map_cond = {
  294. [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
  295. "hi", "ls", "ge", "lt", "gt", "le", "al",
  296. }
  297. local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
  298. ------------------------------------------------------------------------------
  299. -- Output a nicely formatted line with an opcode and operands.
  300. local function putop(ctx, text, operands)
  301. local pos = ctx.pos
  302. local extra = ""
  303. if ctx.rel then
  304. local sym = ctx.symtab[ctx.rel]
  305. if sym then
  306. extra = "\t->"..sym
  307. elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
  308. extra = "\t; 0x"..tohex(ctx.rel)
  309. end
  310. end
  311. if ctx.hexdump > 0 then
  312. ctx.out(format("%08x %s %-5s %s%s\n",
  313. ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
  314. else
  315. ctx.out(format("%08x %-5s %s%s\n",
  316. ctx.addr+pos, text, concat(operands, ", "), extra))
  317. end
  318. ctx.pos = pos + 4
  319. end
  320. -- Fallback for unknown opcodes.
  321. local function unknown(ctx)
  322. return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
  323. end
  324. -- Format operand 2 of load/store opcodes.
  325. local function fmtload(ctx, op, pos)
  326. local base = map_gpr[band(rshift(op, 16), 15)]
  327. local x, ofs
  328. local ext = (band(op, 0x04000000) == 0)
  329. if not ext and band(op, 0x02000000) == 0 then
  330. ofs = band(op, 4095)
  331. if band(op, 0x00800000) == 0 then ofs = -ofs end
  332. if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
  333. ofs = "#"..ofs
  334. elseif ext and band(op, 0x00400000) ~= 0 then
  335. ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
  336. if band(op, 0x00800000) == 0 then ofs = -ofs end
  337. if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
  338. ofs = "#"..ofs
  339. else
  340. ofs = map_gpr[band(op, 15)]
  341. if ext or band(op, 0xfe0) == 0 then
  342. elseif band(op, 0xfe0) == 0x60 then
  343. ofs = format("%s, rrx", ofs)
  344. else
  345. local sh = band(rshift(op, 7), 31)
  346. if sh == 0 then sh = 32 end
  347. ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
  348. end
  349. if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
  350. end
  351. if ofs == "#0" then
  352. x = format("[%s]", base)
  353. elseif band(op, 0x01000000) == 0 then
  354. x = format("[%s], %s", base, ofs)
  355. else
  356. x = format("[%s, %s]", base, ofs)
  357. end
  358. if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
  359. return x
  360. end
  361. -- Disassemble a single instruction.
  362. local function disass_ins(ctx)
  363. local pos = ctx.pos
  364. local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  365. local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
  366. local operands = {}
  367. local suffix = ""
  368. local last, name, pat
  369. ctx.op = op
  370. ctx.rel = nil
  371. local cond = rshift(op, 28)
  372. local opat
  373. if cond == 15 then
  374. opat = map_uncondins[band(rshift(op, 25), 7)]
  375. else
  376. if cond ~= 14 then suffix = map_cond[cond] end
  377. opat = map_condins[band(rshift(op, 25), 7)]
  378. end
  379. while type(opat) ~= "string" do
  380. if not opat then return unknown(ctx) end
  381. opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
  382. end
  383. name, pat = match(opat, "^([a-z0-9]*)(.*)")
  384. for p in gmatch(pat, ".") do
  385. local x = nil
  386. if p == "D" then
  387. x = map_gpr[band(rshift(op, 12), 15)]
  388. elseif p == "N" then
  389. x = map_gpr[band(rshift(op, 16), 15)]
  390. elseif p == "S" then
  391. x = map_gpr[band(rshift(op, 8), 15)]
  392. elseif p == "M" then
  393. x = map_gpr[band(op, 15)]
  394. elseif p == "P" then
  395. if band(op, 0x02000000) ~= 0 then
  396. x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
  397. else
  398. x = map_gpr[band(op, 15)]
  399. if band(op, 0xff0) ~= 0 then
  400. operands[#operands+1] = x
  401. local s = map_shift[band(rshift(op, 5), 3)]
  402. local r = nil
  403. if band(op, 0xf90) == 0 then
  404. if s == "ror" then s = "rrx" else r = "#32" end
  405. elseif band(op, 0x10) == 0 then
  406. r = "#"..band(rshift(op, 7), 31)
  407. else
  408. r = map_gpr[band(rshift(op, 8), 15)]
  409. end
  410. if name == "mov" then name = s; x = r
  411. elseif r then x = format("%s %s", s, r)
  412. else x = s end
  413. end
  414. end
  415. elseif p == "L" then
  416. x = fmtload(ctx, op, pos, false)
  417. elseif p == "B" then
  418. local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
  419. if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
  420. ctx.rel = addr
  421. x = "0x"..tohex(addr)
  422. elseif p == "R" then
  423. if band(op, 0x00200000) ~= 0 and #operands == 1 then
  424. operands[1] = operands[1].."!"
  425. end
  426. local t = {}
  427. for i=0,15 do
  428. if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
  429. end
  430. x = "{"..concat(t, ", ").."}"
  431. elseif p == "W" then
  432. x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
  433. elseif p == "T" then
  434. x = "#0x"..tohex(band(op, 0x00ffffff), 6)
  435. elseif p == "U" then
  436. x = band(rshift(op, 7), 31)
  437. if x == 0 then x = nil end
  438. elseif p == "u" then
  439. x = band(rshift(op, 7), 31)
  440. if band(op, 0x40) == 0 then
  441. if x == 0 then x = nil else x = "lsl #"..x end
  442. else
  443. if x == 0 then x = "asr #32" else x = "asr #"..x end
  444. end
  445. elseif p == "v" then
  446. x = band(rshift(op, 7), 31)
  447. elseif p == "w" then
  448. x = band(rshift(op, 16), 31)
  449. elseif p == "x" then
  450. x = band(rshift(op, 16), 31) + 1
  451. elseif p == "X" then
  452. x = band(rshift(op, 16), 31) - last + 1
  453. elseif p == "K" then
  454. x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
  455. elseif p == "s" then
  456. if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
  457. else
  458. assert(false)
  459. end
  460. if x then
  461. last = x
  462. if type(x) == "number" then x = "#"..x end
  463. operands[#operands+1] = x
  464. end
  465. end
  466. return putop(ctx, name..suffix, operands)
  467. end
  468. ------------------------------------------------------------------------------
  469. -- Disassemble a block of code.
  470. local function disass_block(ctx, ofs, len)
  471. if not ofs then ofs = 0 end
  472. local stop = len and ofs+len or #ctx.code
  473. ctx.pos = ofs
  474. ctx.rel = nil
  475. while ctx.pos < stop do disass_ins(ctx) end
  476. end
  477. -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
  478. local function create_(code, addr, out)
  479. local ctx = {}
  480. ctx.code = code
  481. ctx.addr = addr or 0
  482. ctx.out = out or io.write
  483. ctx.symtab = {}
  484. ctx.disass = disass_block
  485. ctx.hexdump = 8
  486. return ctx
  487. end
  488. -- Simple API: disassemble code (a string) at address and output via out.
  489. local function disass_(code, addr, out)
  490. create_(code, addr, out):disass()
  491. end
  492. -- Return register name for RID.
  493. local function regname_(r)
  494. return map_gpr[r]
  495. end
  496. -- Public module functions.
  497. module(...)
  498. create = create_
  499. disass = disass_
  500. regname = regname_