dis_arm.lua 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. ----------------------------------------------------------------------------
  2. -- LuaJIT ARM disassembler module.
  3. --
  4. -- Copyright (C) 2005-2014 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. 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 = 8, mask = 15,
  24. [10] = {
  25. shift = 20, mask = 1,
  26. [0] = {
  27. shift = 23, mask = 3,
  28. [0] = "vmovFmDN", "vstmFNdr",
  29. _ = {
  30. shift = 21, mask = 1,
  31. [0] = "vstrFdl",
  32. { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
  33. },
  34. },
  35. {
  36. shift = 23, mask = 3,
  37. [0] = "vmovFDNm",
  38. { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
  39. _ = {
  40. shift = 21, mask = 1,
  41. [0] = "vldrFdl", "vldmdbFNdr",
  42. },
  43. },
  44. },
  45. [11] = {
  46. shift = 20, mask = 1,
  47. [0] = {
  48. shift = 23, mask = 3,
  49. [0] = "vmovGmDN", "vstmGNdr",
  50. _ = {
  51. shift = 21, mask = 1,
  52. [0] = "vstrGdl",
  53. { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
  54. },
  55. },
  56. {
  57. shift = 23, mask = 3,
  58. [0] = "vmovGDNm",
  59. { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
  60. _ = {
  61. shift = 21, mask = 1,
  62. [0] = "vldrGdl", "vldmdbGNdr",
  63. },
  64. },
  65. },
  66. _ = {
  67. shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
  68. },
  69. }
  70. local map_vfps = {
  71. shift = 6, mask = 0x2c001,
  72. [0] = "vmlaF.dnm", "vmlsF.dnm",
  73. [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
  74. [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
  75. [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
  76. [0x20000] = "vdivF.dnm",
  77. [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
  78. [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
  79. [0x2c000] = "vmovF.dY",
  80. [0x2c001] = {
  81. shift = 7, mask = 0x1e01,
  82. [0] = "vmovF.dm", "vabsF.dm",
  83. [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
  84. [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
  85. [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
  86. [0x0e01] = "vcvtG.dF.m",
  87. [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
  88. [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
  89. [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
  90. },
  91. }
  92. local map_vfpd = {
  93. shift = 6, mask = 0x2c001,
  94. [0] = "vmlaG.dnm", "vmlsG.dnm",
  95. [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
  96. [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
  97. [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
  98. [0x20000] = "vdivG.dnm",
  99. [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
  100. [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
  101. [0x2c000] = "vmovG.dY",
  102. [0x2c001] = {
  103. shift = 7, mask = 0x1e01,
  104. [0] = "vmovG.dm", "vabsG.dm",
  105. [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
  106. [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
  107. [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
  108. [0x0e01] = "vcvtF.dG.m",
  109. [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
  110. [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
  111. [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
  112. },
  113. }
  114. local map_datac = {
  115. shift = 24, mask = 1,
  116. [0] = {
  117. shift = 4, mask = 1,
  118. [0] = {
  119. shift = 8, mask = 15,
  120. [10] = map_vfps,
  121. [11] = map_vfpd,
  122. -- NYI cdp, mcr, mrc.
  123. },
  124. {
  125. shift = 8, mask = 15,
  126. [10] = {
  127. shift = 20, mask = 15,
  128. [0] = "vmovFnD", "vmovFDn",
  129. [14] = "vmsrD",
  130. [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
  131. },
  132. },
  133. },
  134. "svcT",
  135. }
  136. local map_loadcu = {
  137. shift = 0, mask = 0, -- NYI unconditional CP load/store.
  138. }
  139. local map_datacu = {
  140. shift = 0, mask = 0, -- NYI unconditional CP data.
  141. }
  142. local map_simddata = {
  143. shift = 0, mask = 0, -- NYI SIMD data.
  144. }
  145. local map_simdload = {
  146. shift = 0, mask = 0, -- NYI SIMD load/store, preload.
  147. }
  148. local map_preload = {
  149. shift = 0, mask = 0, -- NYI preload.
  150. }
  151. local map_media = {
  152. shift = 20, mask = 31,
  153. [0] = false,
  154. { --01
  155. shift = 5, mask = 7,
  156. [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
  157. "sadd8DNM", false, false, "ssub8DNM",
  158. },
  159. { --02
  160. shift = 5, mask = 7,
  161. [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
  162. "qadd8DNM", false, false, "qsub8DNM",
  163. },
  164. { --03
  165. shift = 5, mask = 7,
  166. [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
  167. "shadd8DNM", false, false, "shsub8DNM",
  168. },
  169. false,
  170. { --05
  171. shift = 5, mask = 7,
  172. [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
  173. "uadd8DNM", false, false, "usub8DNM",
  174. },
  175. { --06
  176. shift = 5, mask = 7,
  177. [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
  178. "uqadd8DNM", false, false, "uqsub8DNM",
  179. },
  180. { --07
  181. shift = 5, mask = 7,
  182. [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
  183. "uhadd8DNM", false, false, "uhsub8DNM",
  184. },
  185. { --08
  186. shift = 5, mask = 7,
  187. [0] = "pkhbtDNMU", false, "pkhtbDNMU",
  188. { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
  189. "pkhbtDNMU", "selDNM", "pkhtbDNMU",
  190. },
  191. false,
  192. { --0a
  193. shift = 5, mask = 7,
  194. [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
  195. { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
  196. "ssatDxMu", false, "ssatDxMu",
  197. },
  198. { --0b
  199. shift = 5, mask = 7,
  200. [0] = "ssatDxMu", "revDM", "ssatDxMu",
  201. { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
  202. "ssatDxMu", "rev16DM", "ssatDxMu",
  203. },
  204. { --0c
  205. shift = 5, mask = 7,
  206. [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
  207. },
  208. false,
  209. { --0e
  210. shift = 5, mask = 7,
  211. [0] = "usatDwMu", "usat16DwM", "usatDwMu",
  212. { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
  213. "usatDwMu", false, "usatDwMu",
  214. },
  215. { --0f
  216. shift = 5, mask = 7,
  217. [0] = "usatDwMu", "rbitDM", "usatDwMu",
  218. { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
  219. "usatDwMu", "revshDM", "usatDwMu",
  220. },
  221. { --10
  222. shift = 12, mask = 15,
  223. [15] = {
  224. shift = 5, mask = 7,
  225. "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
  226. },
  227. _ = {
  228. shift = 5, mask = 7,
  229. [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
  230. },
  231. },
  232. false, false, false,
  233. { --14
  234. shift = 5, mask = 7,
  235. [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
  236. },
  237. { --15
  238. shift = 5, mask = 7,
  239. [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
  240. { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
  241. false, false, false, false,
  242. "smmlsNMSD", "smmlsrNMSD",
  243. },
  244. false, false,
  245. { --18
  246. shift = 5, mask = 7,
  247. [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
  248. },
  249. false,
  250. { --1a
  251. shift = 5, mask = 3, [2] = "sbfxDMvw",
  252. },
  253. { --1b
  254. shift = 5, mask = 3, [2] = "sbfxDMvw",
  255. },
  256. { --1c
  257. shift = 5, mask = 3,
  258. [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
  259. },
  260. { --1d
  261. shift = 5, mask = 3,
  262. [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
  263. },
  264. { --1e
  265. shift = 5, mask = 3, [2] = "ubfxDMvw",
  266. },
  267. { --1f
  268. shift = 5, mask = 3, [2] = "ubfxDMvw",
  269. },
  270. }
  271. local map_load = {
  272. shift = 21, mask = 9,
  273. {
  274. shift = 20, mask = 5,
  275. [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
  276. },
  277. _ = {
  278. shift = 20, mask = 5,
  279. [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
  280. }
  281. }
  282. local map_load1 = {
  283. shift = 4, mask = 1,
  284. [0] = map_load, map_media,
  285. }
  286. local map_loadm = {
  287. shift = 20, mask = 1,
  288. [0] = {
  289. shift = 23, mask = 3,
  290. [0] = "stmdaNR", "stmNR",
  291. { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
  292. },
  293. {
  294. shift = 23, mask = 3,
  295. [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
  296. "ldmdbNR", "ldmibNR",
  297. },
  298. }
  299. local map_data = {
  300. shift = 21, mask = 15,
  301. [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
  302. "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
  303. "tstNP", "teqNP", "cmpNP", "cmnNP",
  304. "orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
  305. }
  306. local map_mul = {
  307. shift = 21, mask = 7,
  308. [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
  309. "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
  310. }
  311. local map_sync = {
  312. shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
  313. [0] = "swpDMN", false, false, false,
  314. "swpbDMN", false, false, false,
  315. "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
  316. "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
  317. }
  318. local map_mulh = {
  319. shift = 21, mask = 3,
  320. [0] = { shift = 5, mask = 3,
  321. [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
  322. { shift = 5, mask = 3,
  323. [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
  324. { shift = 5, mask = 3,
  325. [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
  326. { shift = 5, mask = 3,
  327. [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
  328. }
  329. local map_misc = {
  330. shift = 4, mask = 7,
  331. -- NYI: decode PSR bits of msr.
  332. [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
  333. { shift = 21, mask = 3, "bxM", false, "clzDM", },
  334. { shift = 21, mask = 3, "bxjM", },
  335. { shift = 21, mask = 3, "blxM", },
  336. false,
  337. { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
  338. false,
  339. { shift = 21, mask = 3, "bkptK", },
  340. }
  341. local map_datar = {
  342. shift = 4, mask = 9,
  343. [9] = {
  344. shift = 5, mask = 3,
  345. [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
  346. { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
  347. { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
  348. { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
  349. },
  350. _ = {
  351. shift = 20, mask = 25,
  352. [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
  353. _ = {
  354. shift = 0, mask = 0xffffffff,
  355. [bor(0xe1a00000)] = "nop",
  356. _ = map_data,
  357. }
  358. },
  359. }
  360. local map_datai = {
  361. shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
  362. [16] = "movwDW", [20] = "movtDW",
  363. [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
  364. [22] = "msrNW",
  365. _ = map_data,
  366. }
  367. local map_branch = {
  368. shift = 24, mask = 1,
  369. [0] = "bB", "blB"
  370. }
  371. local map_condins = {
  372. [0] = map_datar, map_datai, map_load, map_load1,
  373. map_loadm, map_branch, map_loadc, map_datac
  374. }
  375. -- NYI: setend.
  376. local map_uncondins = {
  377. [0] = false, map_simddata, map_simdload, map_preload,
  378. false, "blxB", map_loadcu, map_datacu,
  379. }
  380. ------------------------------------------------------------------------------
  381. local map_gpr = {
  382. [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
  383. "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
  384. }
  385. local map_cond = {
  386. [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
  387. "hi", "ls", "ge", "lt", "gt", "le", "al",
  388. }
  389. local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
  390. ------------------------------------------------------------------------------
  391. -- Output a nicely formatted line with an opcode and operands.
  392. local function putop(ctx, text, operands)
  393. local pos = ctx.pos
  394. local extra = ""
  395. if ctx.rel then
  396. local sym = ctx.symtab[ctx.rel]
  397. if sym then
  398. extra = "\t->"..sym
  399. elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
  400. extra = "\t; 0x"..tohex(ctx.rel)
  401. end
  402. end
  403. if ctx.hexdump > 0 then
  404. ctx.out(format("%08x %s %-5s %s%s\n",
  405. ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
  406. else
  407. ctx.out(format("%08x %-5s %s%s\n",
  408. ctx.addr+pos, text, concat(operands, ", "), extra))
  409. end
  410. ctx.pos = pos + 4
  411. end
  412. -- Fallback for unknown opcodes.
  413. local function unknown(ctx)
  414. return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
  415. end
  416. -- Format operand 2 of load/store opcodes.
  417. local function fmtload(ctx, op, pos)
  418. local base = map_gpr[band(rshift(op, 16), 15)]
  419. local x, ofs
  420. local ext = (band(op, 0x04000000) == 0)
  421. if not ext and band(op, 0x02000000) == 0 then
  422. ofs = band(op, 4095)
  423. if band(op, 0x00800000) == 0 then ofs = -ofs end
  424. if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
  425. ofs = "#"..ofs
  426. elseif ext and band(op, 0x00400000) ~= 0 then
  427. ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
  428. if band(op, 0x00800000) == 0 then ofs = -ofs end
  429. if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
  430. ofs = "#"..ofs
  431. else
  432. ofs = map_gpr[band(op, 15)]
  433. if ext or band(op, 0xfe0) == 0 then
  434. elseif band(op, 0xfe0) == 0x60 then
  435. ofs = format("%s, rrx", ofs)
  436. else
  437. local sh = band(rshift(op, 7), 31)
  438. if sh == 0 then sh = 32 end
  439. ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
  440. end
  441. if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
  442. end
  443. if ofs == "#0" then
  444. x = format("[%s]", base)
  445. elseif band(op, 0x01000000) == 0 then
  446. x = format("[%s], %s", base, ofs)
  447. else
  448. x = format("[%s, %s]", base, ofs)
  449. end
  450. if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
  451. return x
  452. end
  453. -- Format operand 2 of vector load/store opcodes.
  454. local function fmtvload(ctx, op, pos)
  455. local base = map_gpr[band(rshift(op, 16), 15)]
  456. local ofs = band(op, 255)*4
  457. if band(op, 0x00800000) == 0 then ofs = -ofs end
  458. if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
  459. if ofs == 0 then
  460. return format("[%s]", base)
  461. else
  462. return format("[%s, #%d]", base, ofs)
  463. end
  464. end
  465. local function fmtvr(op, vr, sh0, sh1)
  466. if vr == "s" then
  467. return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
  468. else
  469. return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
  470. end
  471. end
  472. -- Disassemble a single instruction.
  473. local function disass_ins(ctx)
  474. local pos = ctx.pos
  475. local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  476. local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
  477. local operands = {}
  478. local suffix = ""
  479. local last, name, pat
  480. local vr
  481. ctx.op = op
  482. ctx.rel = nil
  483. local cond = rshift(op, 28)
  484. local opat
  485. if cond == 15 then
  486. opat = map_uncondins[band(rshift(op, 25), 7)]
  487. else
  488. if cond ~= 14 then suffix = map_cond[cond] end
  489. opat = map_condins[band(rshift(op, 25), 7)]
  490. end
  491. while type(opat) ~= "string" do
  492. if not opat then return unknown(ctx) end
  493. opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
  494. end
  495. name, pat = match(opat, "^([a-z0-9]*)(.*)")
  496. if sub(pat, 1, 1) == "." then
  497. local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
  498. suffix = suffix..s2
  499. pat = p2
  500. end
  501. for p in gmatch(pat, ".") do
  502. local x = nil
  503. if p == "D" then
  504. x = map_gpr[band(rshift(op, 12), 15)]
  505. elseif p == "N" then
  506. x = map_gpr[band(rshift(op, 16), 15)]
  507. elseif p == "S" then
  508. x = map_gpr[band(rshift(op, 8), 15)]
  509. elseif p == "M" then
  510. x = map_gpr[band(op, 15)]
  511. elseif p == "d" then
  512. x = fmtvr(op, vr, 12, 22)
  513. elseif p == "n" then
  514. x = fmtvr(op, vr, 16, 7)
  515. elseif p == "m" then
  516. x = fmtvr(op, vr, 0, 5)
  517. elseif p == "P" then
  518. if band(op, 0x02000000) ~= 0 then
  519. x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
  520. else
  521. x = map_gpr[band(op, 15)]
  522. if band(op, 0xff0) ~= 0 then
  523. operands[#operands+1] = x
  524. local s = map_shift[band(rshift(op, 5), 3)]
  525. local r = nil
  526. if band(op, 0xf90) == 0 then
  527. if s == "ror" then s = "rrx" else r = "#32" end
  528. elseif band(op, 0x10) == 0 then
  529. r = "#"..band(rshift(op, 7), 31)
  530. else
  531. r = map_gpr[band(rshift(op, 8), 15)]
  532. end
  533. if name == "mov" then name = s; x = r
  534. elseif r then x = format("%s %s", s, r)
  535. else x = s end
  536. end
  537. end
  538. elseif p == "L" then
  539. x = fmtload(ctx, op, pos)
  540. elseif p == "l" then
  541. x = fmtvload(ctx, op, pos)
  542. elseif p == "B" then
  543. local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
  544. if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
  545. ctx.rel = addr
  546. x = "0x"..tohex(addr)
  547. elseif p == "F" then
  548. vr = "s"
  549. elseif p == "G" then
  550. vr = "d"
  551. elseif p == "." then
  552. suffix = suffix..(vr == "s" and ".f32" or ".f64")
  553. elseif p == "R" then
  554. if band(op, 0x00200000) ~= 0 and #operands == 1 then
  555. operands[1] = operands[1].."!"
  556. end
  557. local t = {}
  558. for i=0,15 do
  559. if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
  560. end
  561. x = "{"..concat(t, ", ").."}"
  562. elseif p == "r" then
  563. if band(op, 0x00200000) ~= 0 and #operands == 2 then
  564. operands[1] = operands[1].."!"
  565. end
  566. local s = tonumber(sub(last, 2))
  567. local n = band(op, 255)
  568. if vr == "d" then n = rshift(n, 1) end
  569. operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
  570. elseif p == "W" then
  571. x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
  572. elseif p == "T" then
  573. x = "#0x"..tohex(band(op, 0x00ffffff), 6)
  574. elseif p == "U" then
  575. x = band(rshift(op, 7), 31)
  576. if x == 0 then x = nil end
  577. elseif p == "u" then
  578. x = band(rshift(op, 7), 31)
  579. if band(op, 0x40) == 0 then
  580. if x == 0 then x = nil else x = "lsl #"..x end
  581. else
  582. if x == 0 then x = "asr #32" else x = "asr #"..x end
  583. end
  584. elseif p == "v" then
  585. x = band(rshift(op, 7), 31)
  586. elseif p == "w" then
  587. x = band(rshift(op, 16), 31)
  588. elseif p == "x" then
  589. x = band(rshift(op, 16), 31) + 1
  590. elseif p == "X" then
  591. x = band(rshift(op, 16), 31) - last + 1
  592. elseif p == "Y" then
  593. x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
  594. elseif p == "K" then
  595. x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
  596. elseif p == "s" then
  597. if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
  598. else
  599. assert(false)
  600. end
  601. if x then
  602. last = x
  603. if type(x) == "number" then x = "#"..x end
  604. operands[#operands+1] = x
  605. end
  606. end
  607. return putop(ctx, name..suffix, operands)
  608. end
  609. ------------------------------------------------------------------------------
  610. -- Disassemble a block of code.
  611. local function disass_block(ctx, ofs, len)
  612. if not ofs then ofs = 0 end
  613. local stop = len and ofs+len or #ctx.code
  614. ctx.pos = ofs
  615. ctx.rel = nil
  616. while ctx.pos < stop do disass_ins(ctx) end
  617. end
  618. -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
  619. local function create_(code, addr, out)
  620. local ctx = {}
  621. ctx.code = code
  622. ctx.addr = addr or 0
  623. ctx.out = out or io.write
  624. ctx.symtab = {}
  625. ctx.disass = disass_block
  626. ctx.hexdump = 8
  627. return ctx
  628. end
  629. -- Simple API: disassemble code (a string) at address and output via out.
  630. local function disass_(code, addr, out)
  631. create_(code, addr, out):disass()
  632. end
  633. -- Return register name for RID.
  634. local function regname_(r)
  635. if r < 16 then return map_gpr[r] end
  636. return "d"..(r-16)
  637. end
  638. -- Public module functions.
  639. module(...)
  640. create = create_
  641. disass = disass_
  642. regname = regname_