disarm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * Copyright (c) 2012 Wojtek Kaniewski <wojtekka@toxygen.net>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to
  6. * deal in the Software without restriction, including without limitation the
  7. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. * sell copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. * IN THE SOFTWARE.
  21. */
  22. #include <stdio.h>
  23. #include <string.h>
  24. #define IMM_FORMAT "0x%x"
  25. //#define IMM_FORMAT "%d"
  26. #define ADDR_FORMAT "0x%x"
  27. static inline unsigned int rol(unsigned int value, unsigned int shift)
  28. {
  29. shift &= 31;
  30. return (value >> shift) | (value << (32 - shift));
  31. }
  32. static inline const char *condition(unsigned int insn)
  33. {
  34. const char *conditions[16] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", "nv" };
  35. return conditions[(insn >> 28) & 0x0f];
  36. }
  37. static inline const char *register_name(unsigned int reg)
  38. {
  39. const char *register_names[16] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" };
  40. return register_names[reg & 0x0f];
  41. }
  42. static const char *register_list(unsigned int list, char *buf, size_t buf_len)
  43. {
  44. int i;
  45. buf[0] = 0;
  46. for (i = 0; i < 16; i++)
  47. {
  48. if ((list >> i) & 1)
  49. {
  50. snprintf(buf + strlen(buf), buf_len - strlen(buf), "%s%s", (buf[0] == 0) ? "" : ",", register_name(i));
  51. }
  52. }
  53. return buf;
  54. }
  55. static const char *shift(unsigned int insn, char *buf, size_t buf_len)
  56. {
  57. unsigned int imm = (insn >> 7) & 0x1f;
  58. const char *rn = register_name(insn >> 8);
  59. unsigned int type = (insn >> 4) & 0x07;
  60. switch (type)
  61. {
  62. case 0:
  63. snprintf(buf, buf_len, (imm != 0) ? ",lsl #%d" : "", imm);
  64. break;
  65. case 1:
  66. snprintf(buf, buf_len, ",lsl %s", rn);
  67. break;
  68. case 2:
  69. snprintf(buf, buf_len, ",lsr #%d", imm ? imm : 32);
  70. break;
  71. case 3:
  72. snprintf(buf, buf_len, ",lsr %s", rn);
  73. break;
  74. case 4:
  75. snprintf(buf, buf_len, ",asr #%d", imm ? imm : 32);
  76. break;
  77. case 5:
  78. snprintf(buf, buf_len, ",asr %s", rn);
  79. break;
  80. case 6:
  81. snprintf(buf, buf_len, (imm != 0) ? ",ror #%d" : ",rrx", imm);
  82. break;
  83. case 7:
  84. snprintf(buf, buf_len, ",ror %s", rn);
  85. break;
  86. }
  87. return buf;
  88. }
  89. static const char *immediate(unsigned int imm, int negative, int show_if_zero, char *buf, size_t buf_len)
  90. {
  91. if (imm || show_if_zero)
  92. {
  93. snprintf(buf, buf_len, ",#%s" IMM_FORMAT, (negative) ? "-" : "", imm);
  94. return buf;
  95. }
  96. return "";
  97. }
  98. static int data_processing(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  99. {
  100. unsigned int oper = (insn >> 21) & 15;
  101. const char *names[16] = { "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" };
  102. const char *name;
  103. const char *s;
  104. unsigned int rd;
  105. unsigned int rn;
  106. int is_move = ((oper == 13) || (oper == 15));
  107. int is_test = ((oper >= 8) && (oper <= 11));
  108. char tmp_buf[64];
  109. name = names[oper];
  110. s = ((insn >> 20) & 1) ? "s" : "";
  111. rn = (insn >> 16) & 15;
  112. rd = (insn >> 12) & 15;
  113. /* mov r0,r0,r0 is a nop */
  114. if (insn == 0xe1a00000)
  115. {
  116. snprintf(buf, buf_len, "nop");
  117. return 1;
  118. }
  119. /* mrs */
  120. if ((insn & 0x0fbf0fff) == 0x010f0000)
  121. {
  122. const char *psr = ((insn >> 22) & 1) ? "spsr" : "cpsr";
  123. const char *rd = register_name(insn >> 12);
  124. snprintf(buf, buf_len, "mrs%s %s,%s", condition(insn), rd, psr);
  125. return 1;
  126. }
  127. /* msr flag only*/
  128. if ((insn & 0x0db0f000) == 0x0120f000)
  129. {
  130. const char *psr = ((insn >> 22) & 1) ? "spsr" : "cpsr";
  131. const char *suffix;
  132. switch ((insn >> 16) & 15)
  133. {
  134. case 9:
  135. suffix = "";
  136. break;
  137. case 8:
  138. suffix = "_f";
  139. break;
  140. case 1:
  141. suffix = "_c";
  142. break;
  143. default:
  144. return 0;
  145. }
  146. if ((insn >> 25) & 1)
  147. {
  148. unsigned int imm = rol(insn & 0x000000ff, ((insn >> 8) & 15) * 2);
  149. snprintf(buf, buf_len, "msr%s %s%s,#" IMM_FORMAT, condition(insn), psr, suffix, imm);
  150. }
  151. else
  152. {
  153. const char *rm = register_name(insn >> 0);
  154. if (((insn >> 4) & 255) != 0)
  155. {
  156. return 0;
  157. }
  158. snprintf(buf, buf_len, "msr%s %s%s,%s", condition(insn), psr, suffix, rm);
  159. }
  160. return 1;
  161. }
  162. if (((insn >> 25) & 1) == 0)
  163. {
  164. unsigned int rm;
  165. rm = (insn & 15);
  166. if (is_move)
  167. {
  168. snprintf(buf, buf_len, "%s%s%s %s,%s%s", name, condition(insn), s, register_name(rd), register_name(rm), shift(insn, tmp_buf, sizeof(tmp_buf)));
  169. }
  170. else if (is_test)
  171. {
  172. snprintf(buf, buf_len, "%s%s %s,%s%s", name, condition(insn), register_name(rn), register_name(rm), shift(insn, tmp_buf, sizeof(tmp_buf)));
  173. }
  174. else
  175. {
  176. snprintf(buf, buf_len, "%s%s%s %s,%s,%s%s", name, condition(insn), s, register_name(rd), register_name(rn), register_name(rm), shift(insn, tmp_buf, sizeof(tmp_buf)));
  177. }
  178. }
  179. else
  180. {
  181. unsigned int imm;
  182. imm = rol(insn & 0x000000ff, ((insn >> 8) & 15) * 2);
  183. if (is_move)
  184. {
  185. snprintf(buf, buf_len, "%s%s%s %s%s", name, condition(insn), s, register_name(rd), immediate(imm, 0, 1, tmp_buf, sizeof(tmp_buf)));
  186. }
  187. else if (is_test)
  188. {
  189. snprintf(buf, buf_len, "%s%s %s%s", name, condition(insn), register_name(rn), immediate(imm, 0, 1, tmp_buf, sizeof(tmp_buf)));
  190. }
  191. else
  192. {
  193. snprintf(buf, buf_len, "%s%s%s %s,%s%s", name, condition(insn), s, register_name(rd), register_name(rn), immediate(imm, 0, 1, tmp_buf, sizeof(tmp_buf)));
  194. }
  195. }
  196. return 1;
  197. }
  198. static int branch(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  199. {
  200. const char *link = ((insn >> 24) & 1) ? "l" : "";
  201. unsigned int address;
  202. unsigned int offset;
  203. offset = insn & 0x00ffffff;
  204. if ((offset & 0x00800000) != 0)
  205. {
  206. offset |= 0xff000000;
  207. }
  208. address = pc + 8 + (offset << 2);
  209. snprintf(buf, buf_len, "b%s%s " ADDR_FORMAT, link, condition(insn), address);
  210. return 1;
  211. }
  212. static int multiply(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  213. {
  214. const char *rd = register_name(insn >> 16);
  215. const char *rn = register_name(insn >> 12);
  216. const char *rs = register_name(insn >> 8);
  217. const char *rm = register_name(insn >> 0);
  218. const char *s = ((insn >> 20) & 1) ? "s" : "";
  219. int mla = (insn >> 21) & 1;
  220. snprintf(buf, buf_len, (mla) ? "mla%s%s %s,%s,%s,%s" : "mul%s%s %s,%s,%s", condition(insn), s, rd, rm, rs, rn);
  221. return 1;
  222. }
  223. static int multiply_long(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  224. {
  225. const char *rh = register_name(insn >> 16);
  226. const char *rl = register_name(insn >> 12);
  227. const char *rs = register_name(insn >> 8);
  228. const char *rm = register_name(insn >> 0);
  229. const char *u = ((insn >> 22) & 1) ? "s" : "u";
  230. const char *s = ((insn >> 20) & 1) ? "s" : "";
  231. const char *name = ((insn >> 21) & 1) ? "mlal" : "mull";
  232. snprintf(buf, buf_len, "%s%s%s%s %s,%s,%s,%s", u, name, condition(insn), s, rl, rh, rm, rs);
  233. return 1;
  234. }
  235. static int single_data_swap(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  236. {
  237. const char *rn = register_name(insn >> 16);
  238. const char *rd = register_name(insn >> 12);
  239. const char *rm = register_name(insn >> 0);
  240. const char *b = ((insn >> 22) & 1) ? "b" : "";
  241. snprintf(buf, buf_len, "swp%s%s %s,%s,[%s]", condition(insn), b, rd, rm, rn);
  242. return 1;
  243. }
  244. static int branch_and_exchange(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  245. {
  246. const char *rn = register_name(insn >> 0);
  247. const char *l = ((insn >> 5) & 1) ? "l" : "";
  248. snprintf(buf, buf_len, "b%sx%s %s", l, condition(insn), rn);
  249. return 1;
  250. }
  251. static int halfword_data_transfer(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  252. {
  253. const char *rn = register_name(insn >> 16);
  254. const char *rd = register_name(insn >> 12);
  255. const char *name = ((insn >> 20) & 1) ? "ldr" : "str";
  256. const char *w = ((insn >> 21) & 1) ? "!" : "";
  257. int sign = (insn >> 23) & 1;
  258. int pre = (insn >> 24) & 1;
  259. const char *suffix = "";
  260. char tmp_buf[64];
  261. switch ((insn >> 5) & 3)
  262. {
  263. case 0:
  264. name = "swp";
  265. break;
  266. case 1:
  267. suffix = "h";
  268. break;
  269. case 2:
  270. suffix = "sb";
  271. break;
  272. case 3:
  273. suffix = "sh";
  274. break;
  275. }
  276. if ((insn >> 22) & 1)
  277. {
  278. unsigned int imm = ((insn >> 4) & 0xf0) | (insn & 0x0f);
  279. snprintf(buf, buf_len, (pre) ? "%s%s%s %s,[%s%s]%s" : "%s%s%s %s,[%s],%s%s", name, condition(insn), suffix, rd, rn, immediate(imm, !sign, 0, tmp_buf, sizeof(tmp_buf)), w);
  280. }
  281. else
  282. {
  283. const char *rm = register_name(insn >> 0);
  284. snprintf(buf, buf_len, (pre) ? "%s%s%s %s,[%s,%s%s]%s" : "%s%s%s %s,[%s],%s%s%s", name, condition(insn), suffix, rd, rn, sign ? "" : "-", rm, w);
  285. }
  286. return 1;
  287. }
  288. static int single_data_transfer(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  289. {
  290. const char *rn = register_name(insn >> 16);
  291. const char *rd = register_name(insn >> 12);
  292. const char *name = ((insn >> 20) & 1) ? "ldr" : "str";
  293. const char *w = ((insn >> 21) & 1) ? "!" : "";
  294. const char *b = ((insn >> 22) & 1) ? "b" : "";
  295. int sign = (insn >> 23) & 1;
  296. int pre = (insn >> 24) & 1;
  297. char tmp_buf[64];
  298. if ((insn >> 25) & 1)
  299. {
  300. const char *rm = register_name(insn >> 0);
  301. snprintf(buf, buf_len, (pre) ? "%s%s%s %s,[%s,%s%s%s]%s" : "%s%s%s %s,[%s],%s%s%s%s", name, condition(insn), b, rd, rn, sign ? "" : "-", rm, shift(insn, tmp_buf, sizeof(tmp_buf)), w);
  302. }
  303. else
  304. {
  305. unsigned int imm = insn & 0x00000fff;
  306. snprintf(buf, buf_len, (pre) ? "%s%s%s %s,[%s%s]%s" : "%s%s%s %s,[%s]%s%s", name, condition(insn), b, rd, rn, immediate(imm, !sign, 0, tmp_buf, sizeof(tmp_buf)), w);
  307. }
  308. return 1;
  309. }
  310. static int block_data_transfer(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  311. {
  312. const char *s = ((insn >> 22) & 1) ? "^" : "";
  313. const char *w = ((insn >> 21) & 1) ? "!" : "";
  314. int load = (insn >> 20) & 1;
  315. const char *name = (load) ? "ldm" : "stm";
  316. const char *ldm_stubs[4] = { "fa", "fd", "ea", "ed" };
  317. const char *stm_stubs[4] = { "ed", "ea", "fd", "fa" };
  318. int stub_idx = (insn >> 23) & 3;
  319. const char *stub = (load) ? ldm_stubs[stub_idx] : stm_stubs[stub_idx];
  320. char tmp_buf[64];
  321. snprintf(buf, buf_len, "%s%s%s %s%s, {%s}%s", name, condition(insn), stub, register_name(insn >> 16), w, register_list(insn & 0xffff, tmp_buf, sizeof(tmp_buf)), s);
  322. return 1;
  323. }
  324. static int coprocessor_data_transfer(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  325. {
  326. const char *name = ((insn >> 20) & 1) ? "ldc" : "stc";
  327. const char *rn = register_name(insn >> 16);
  328. int sign = (insn >> 23) & 1;
  329. const char *l = ((insn >> 22) & 1) ? "l" : "";
  330. const char *w = ((insn >> 21) & 1) ? "!" : "";
  331. int pre = (insn >> 24) & 1;
  332. unsigned int cp = (insn >> 8) & 15;
  333. unsigned int cd = (insn >> 12) & 15;
  334. unsigned int imm = (insn >> 0) & 255;
  335. char tmp_buf[64];
  336. snprintf(buf, buf_len, (pre) ? "%s%s%s p%d,cr%d,[%s%s]%s" : "%s%s%s p%d,cr%d,[%s]%s%s", name, condition(insn), l, cp, cd, rn, immediate(imm, !sign, 0, tmp_buf, sizeof(tmp_buf)), w);
  337. return 1;
  338. }
  339. static int coprocessor_data_operation(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  340. {
  341. snprintf(buf, buf_len, "cdp%s p%d,%d,cr%d,cr%d,cr%d,{%d}", condition(insn), (insn >> 8) & 15, (insn >> 20) & 15, (insn >> 12) & 15, (insn >> 16) & 15, (insn >> 0) & 15, (insn >> 5) & 7);
  342. return 1;
  343. }
  344. static int coprocessor_register_transfer(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  345. {
  346. const char *name = ((insn >> 20) & 1) ? "mrc" : "mcr";
  347. unsigned int cn = (insn >> 16) & 15;
  348. const char *rd = register_name(insn >> 12);
  349. unsigned int expr1 = (insn >> 21) & 7;
  350. unsigned int expr2 = (insn >> 5) & 7;
  351. unsigned int cp = (insn >> 8) & 15;
  352. unsigned int cm = (insn >> 0) & 15;
  353. snprintf(buf, buf_len, "%s%s p%d,%d,%s,cr%d,cr%d,{%d}", name, condition(insn), cp, expr1, rd, cn, cm, expr2);
  354. return 1;
  355. }
  356. static int software_interrupt(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
  357. {
  358. snprintf(buf, buf_len, "swi%s %u", condition(insn), insn & 0x00ffffff);
  359. return 1;
  360. }
  361. int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, unsigned long *addr)
  362. {
  363. *addr = 0;
  364. if ((insn & 0x0fffffd0) == 0x012fff10)
  365. return branch_and_exchange(pc, insn, buf, buf_len);
  366. if ((insn & 0x0fb00ff0) == 0x01000090)
  367. return single_data_swap(pc, insn, buf, buf_len);
  368. if ((insn & 0x0fc000f0) == 0x00000090)
  369. return multiply(pc, insn, buf, buf_len);
  370. if ((insn & 0x0f8000f0) == 0x00800090)
  371. return multiply_long(pc, insn, buf, buf_len);
  372. if ((insn & 0x0f000010) == 0x0e000000)
  373. return coprocessor_data_operation(pc, insn, buf, buf_len);
  374. if ((insn & 0x0f000010) == 0x0e000010)
  375. return coprocessor_register_transfer(pc, insn, buf, buf_len);
  376. if ((insn & 0x0f000000) == 0x0f000000)
  377. return software_interrupt(pc, insn, buf, buf_len);
  378. if ((insn & 0x0e000090) == 0x00000090)
  379. return halfword_data_transfer(pc, insn, buf, buf_len);
  380. if ((insn & 0x0e000000) == 0x08000000)
  381. return block_data_transfer(pc, insn, buf, buf_len);
  382. if ((insn & 0x0e000000) == 0x0a000000) {
  383. *addr = (unsigned long)pc+8 + ((unsigned long)(insn << 8) >> 6);
  384. return branch(pc, insn, buf, buf_len);
  385. }
  386. if ((insn & 0x0e000000) == 0x0c000000)
  387. return coprocessor_data_transfer(pc, insn, buf, buf_len);
  388. if ((insn & 0x0c000000) == 0x00000000)
  389. return data_processing(pc, insn, buf, buf_len);
  390. if ((insn & 0x0c000000) == 0x04000000)
  391. return single_data_transfer(pc, insn, buf, buf_len);
  392. return 0;
  393. }