/opengles/src/codegen/arm-dis.c

http://ftk.googlecode.com/ · C · 494 lines · 361 code · 87 blank · 46 comment · 158 complexity · a9c099dbe546495250863c5851e520da MD5 · raw file

  1. /*
  2. * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
  3. *
  4. * Copyright (c) 2002 Wild West Software
  5. * Copyright (c) 2001, 2002 Sergey Chaban
  6. *
  7. * Permission is hereby granted, free of charge, to any person
  8. * obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without restriction,
  10. * including without limitation the rights to use, copy, modify, merge,
  11. * publish, distribute, sublicense, and/or sell copies of the Software,
  12. * and to permit persons to whom the Software is furnished to do so,
  13. * subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included
  16. * in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  20. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  21. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  22. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  24. * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. */
  27. #include <stdarg.h>
  28. #include "arm-dis.h"
  29. #include "arm-codegen.h"
  30. static const ARMDis* gdisasm = NULL;
  31. static const int use_reg_alias = 1;
  32. const static char* cond[] = {
  33. "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
  34. "hi", "ls", "ge", "lt", "gt", "le", "", "nv"
  35. };
  36. const static char* ops[] = {
  37. "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
  38. "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn"
  39. };
  40. const static char* shift_types[] = {"lsl", "lsr", "asr", "ror"};
  41. const static char* mul_ops[] = {
  42. "mul", "mla", "?", "?", "umull", "umlal", "smull", "smlal"
  43. };
  44. const static char* reg_alias[] = {
  45. "a1", "a2", "a3", "a4",
  46. "r4", "r5", "r6", "r7", "r8", "r9", "r10",
  47. "fp", "ip", "sp", "lr", "pc"
  48. };
  49. const static char* msr_fld[] = {"f", "c", "x", "?", "s"};
  50. /* private functions prototypes (to keep compiler happy) */
  51. void chk_out(ARMDis* dis);
  52. void dump_reg(ARMDis* dis, int reg);
  53. void dump_creg(ARMDis* dis, int creg);
  54. void dump_reglist(ARMDis* dis, int reg_list);
  55. void init_gdisasm(void);
  56. void dump_br(ARMDis* dis, ARMInstr i);
  57. void dump_cdp(ARMDis* dis, ARMInstr i);
  58. void dump_cdt(ARMDis* dis, ARMInstr i);
  59. void dump_crt(ARMDis* dis, ARMInstr i);
  60. void dump_dpi(ARMDis* dis, ARMInstr i);
  61. void dump_hxfer(ARMDis* dis, ARMInstr i);
  62. void dump_mrs(ARMDis* dis, ARMInstr i);
  63. void dump_mrt(ARMDis* dis, ARMInstr i);
  64. void dump_msr(ARMDis* dis, ARMInstr i);
  65. void dump_mul(ARMDis* dis, ARMInstr i);
  66. void dump_swi(ARMDis* dis, ARMInstr i);
  67. void dump_swp(ARMDis* dis, ARMInstr i);
  68. void dump_wxfer(ARMDis* dis, ARMInstr i);
  69. void dump_clz(ARMDis* dis, ARMInstr i);
  70. /*
  71. void out(ARMDis* dis, const char* format, ...) {
  72. va_list arglist;
  73. va_start(arglist, format);
  74. fprintf(dis->dis_out, format, arglist);
  75. va_end(arglist);
  76. }
  77. */
  78. void chk_out(ARMDis* dis) {
  79. if (dis != NULL && dis->dis_out == NULL) dis->dis_out = stdout;
  80. }
  81. void armdis_set_output(ARMDis* dis, FILE* f) {
  82. if (dis != NULL) {
  83. dis->dis_out = f;
  84. chk_out(dis);
  85. }
  86. }
  87. FILE* armdis_get_output(ARMDis* dis) {
  88. return (dis != NULL ? dis->dis_out : NULL);
  89. }
  90. void dump_reg(ARMDis* dis, int reg) {
  91. reg &= 0xF;
  92. if (!use_reg_alias || (reg > 3 && reg < 11)) {
  93. fprintf(dis->dis_out, "r%d", reg);
  94. } else {
  95. fprintf(dis->dis_out, reg_alias[reg]);
  96. }
  97. }
  98. void dump_creg(ARMDis* dis, int creg) {
  99. if (dis != NULL) {
  100. creg &= 0xF;
  101. fprintf(dis->dis_out, "c%d", creg);
  102. }
  103. }
  104. void dump_reglist(ARMDis* dis, int reg_list) {
  105. int i = 0, j, n = 0;
  106. int m1 = 1, m2, rn;
  107. while (i < 16) {
  108. if ((reg_list & m1) != 0) {
  109. if (n != 0) fprintf(dis->dis_out, ", ");
  110. n++;
  111. dump_reg(dis, i);
  112. for (j = i+1, rn = 0, m2 = m1<<1; j < 16; ++j, m2<<=1) {
  113. if ((reg_list & m2) != 0) ++rn;
  114. else break;
  115. }
  116. i+=rn;
  117. if (rn > 1) {
  118. fprintf(dis->dis_out, "-");
  119. dump_reg(dis, i);
  120. } else if (rn == 1) {
  121. fprintf(dis->dis_out, ", ");
  122. dump_reg(dis, i);
  123. }
  124. m1<<=(rn+1);
  125. i++;
  126. } else {
  127. ++i;
  128. m1<<=1;
  129. }
  130. }
  131. }
  132. void dump_br(ARMDis* dis, ARMInstr i) {
  133. fprintf(dis->dis_out, "b%s%s\t%x\t; %x -> %x",
  134. (i.br.link == 1) ? "l" : "",
  135. cond[i.br.cond], i.br.offset, dis->offset, (int)dis->offset + 4*2 + ((int)(i.br.offset << 8) >> 6));
  136. }
  137. void dump_dpi(ARMDis* dis, ARMInstr i) {
  138. fprintf(dis->dis_out, "%s%s", ops[i.dpi.all.opcode], cond[i.dpi.all.cond]);
  139. if ((i.dpi.all.opcode < ARMOP_TST || i.dpi.all.opcode > ARMOP_CMN) && (i.dpi.all.s != 0)) {
  140. fprintf(dis->dis_out, "s");
  141. }
  142. fprintf(dis->dis_out, "\t");
  143. if ((i.dpi.all.opcode < ARMOP_TST) || (i.dpi.all.opcode > ARMOP_CMN)) {
  144. /* for comparison operations Rd is ignored */
  145. dump_reg(dis, i.dpi.all.rd);
  146. fprintf(dis->dis_out, ", ");
  147. }
  148. if ((i.dpi.all.opcode != ARMOP_MOV) && (i.dpi.all.opcode != ARMOP_MVN)) {
  149. /* for MOV/MVN Rn is ignored */
  150. dump_reg(dis, i.dpi.all.rn);
  151. fprintf(dis->dis_out, ", ");
  152. }
  153. if (i.dpi.all.type == 1) {
  154. /* immediate */
  155. if (i.dpi.op2_imm.rot != 0) {
  156. fprintf(dis->dis_out, "#%d, %d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.rot << 1,
  157. ARM_SCALE(i.dpi.op2_imm.imm, (i.dpi.op2_imm.rot << 1)) );
  158. } else {
  159. fprintf(dis->dis_out, "#%d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.imm);
  160. }
  161. } else {
  162. /* reg-reg */
  163. if (i.dpi.op2_reg.tag == 0) {
  164. /* op2 is reg shift by imm */
  165. dump_reg(dis, i.dpi.op2_reg_imm.r2.rm);
  166. if (i.dpi.op2_reg_imm.imm.shift != 0) {
  167. fprintf(dis->dis_out, " %s #%d", shift_types[i.dpi.op2_reg_imm.r2.type], i.dpi.op2_reg_imm.imm.shift);
  168. }
  169. } else {
  170. /* op2 is reg shift by reg */
  171. dump_reg(dis, i.dpi.op2_reg_reg.r2.rm);
  172. fprintf(dis->dis_out, " %s ", shift_types[i.dpi.op2_reg_reg.r2.type]);
  173. dump_reg(dis, i.dpi.op2_reg_reg.reg.rs);
  174. }
  175. }
  176. }
  177. void dump_wxfer(ARMDis* dis, ARMInstr i) {
  178. fprintf(dis->dis_out, "%s%s%s%s\t",
  179. (i.wxfer.all.ls == 0) ? "str" : "ldr",
  180. cond[i.generic.cond],
  181. (i.wxfer.all.b == 0) ? "" : "b",
  182. (i.wxfer.all.ls != 0 && i.wxfer.all.wb != 0) ? "t" : "");
  183. dump_reg(dis, i.wxfer.all.rd);
  184. fprintf(dis->dis_out, ", [");
  185. dump_reg(dis, i.wxfer.all.rn);
  186. fprintf(dis->dis_out, "%s, ", (i.wxfer.all.p == 0) ? "]" : "");
  187. if (i.wxfer.all.type == 0) { /* imm */
  188. fprintf(dis->dis_out, "#%s%d", (i.wxfer.all.u == 0) ? "-" : "", i.wxfer.all.op2_imm);
  189. } else {
  190. dump_reg(dis, i.wxfer.op2_reg_imm.r2.rm);
  191. if (i.wxfer.op2_reg_imm.imm.shift != 0) {
  192. fprintf(dis->dis_out, " %s #%d", shift_types[i.wxfer.op2_reg_imm.r2.type], i.wxfer.op2_reg_imm.imm.shift);
  193. }
  194. }
  195. if (i.wxfer.all.p != 0) {
  196. /* close pre-index instr, also check for write-back */
  197. fprintf(dis->dis_out, "]%s", (i.wxfer.all.wb != 0) ? "!" : "");
  198. }
  199. }
  200. void dump_hxfer(ARMDis* dis, ARMInstr i) {
  201. fprintf(dis->dis_out, "%s%s%s%s\t",
  202. (i.hxfer.ls == 0) ? "str" : "ldr",
  203. cond[i.generic.cond],
  204. (i.hxfer.s != 0) ? "s" : "",
  205. (i.hxfer.h != 0) ? "h" : "b");
  206. dump_reg(dis, i.hxfer.rd);
  207. fprintf(dis->dis_out, ", [");
  208. dump_reg(dis, i.hxfer.rn);
  209. fprintf(dis->dis_out, "%s, ", (i.hxfer.p == 0) ? "]" : "");
  210. if (i.hxfer.type != 0) { /* imm */
  211. fprintf(dis->dis_out, "#%s%d", (i.hxfer.u == 0) ? "-" : "", (i.hxfer.imm_hi << 4) | i.hxfer.rm);
  212. } else {
  213. dump_reg(dis, i.hxfer.rm);
  214. }
  215. if (i.hxfer.p != 0) {
  216. /* close pre-index instr, also check for write-back */
  217. fprintf(dis->dis_out, "]%s", (i.hxfer.wb != 0) ? "!" : "");
  218. }
  219. }
  220. void dump_mrt(ARMDis* dis, ARMInstr i) {
  221. fprintf(dis->dis_out, "%s%s%s%s\t", (i.mrt.ls == 0) ? "stm" : "ldm", cond[i.mrt.cond],
  222. (i.mrt.u == 0) ? "d" : "i", (i.mrt.p == 0) ? "a" : "b");
  223. dump_reg(dis, i.mrt.rn);
  224. fprintf(dis->dis_out, "%s, {", (i.mrt.wb != 0) ? "!" : "");
  225. dump_reglist(dis, i.mrt.reg_list);
  226. fprintf(dis->dis_out, "}");
  227. }
  228. void dump_swp(ARMDis* dis, ARMInstr i) {
  229. fprintf(dis->dis_out, "swp%s%s ", cond[i.swp.cond], (i.swp.b != 0) ? "b" : "");
  230. dump_reg(dis, i.swp.rd);
  231. fprintf(dis->dis_out, ", ");
  232. dump_reg(dis, i.swp.rm);
  233. fprintf(dis->dis_out, ", [");
  234. dump_reg(dis, i.swp.rn);
  235. fprintf(dis->dis_out, "]");
  236. }
  237. void dump_mul(ARMDis* dis, ARMInstr i) {
  238. fprintf(dis->dis_out, "%s%s%s\t", mul_ops[i.mul.opcode], cond[i.mul.cond], (i.mul.s != 0) ? "s" : "");
  239. switch (i.mul.opcode) {
  240. case ARMOP_MUL:
  241. dump_reg(dis, i.mul.rd);
  242. fprintf(dis->dis_out, ", ");
  243. dump_reg(dis, i.mul.rm);
  244. fprintf(dis->dis_out, ", ");
  245. dump_reg(dis, i.mul.rs);
  246. break;
  247. case ARMOP_MLA:
  248. dump_reg(dis, i.mul.rd);
  249. fprintf(dis->dis_out, ", ");
  250. dump_reg(dis, i.mul.rm);
  251. fprintf(dis->dis_out, ", ");
  252. dump_reg(dis, i.mul.rs);
  253. fprintf(dis->dis_out, ", ");
  254. dump_reg(dis, i.mul.rn);
  255. break;
  256. case ARMOP_UMULL:
  257. case ARMOP_UMLAL:
  258. case ARMOP_SMULL:
  259. case ARMOP_SMLAL:
  260. dump_reg(dis, i.mul.rd);
  261. fprintf(dis->dis_out, ", ");
  262. dump_reg(dis, i.mul.rn);
  263. fprintf(dis->dis_out, ", ");
  264. dump_reg(dis, i.mul.rm);
  265. fprintf(dis->dis_out, ", ");
  266. dump_reg(dis, i.mul.rs);
  267. break;
  268. default:
  269. fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", i.raw);
  270. break;
  271. }
  272. }
  273. void dump_cdp(ARMDis* dis, ARMInstr i) {
  274. fprintf(dis->dis_out, "cdp%s\tp%d, %d, ", cond[i.generic.cond], i.cdp.cpn, i.cdp.op);
  275. dump_creg(dis, i.cdp.crd);
  276. fprintf(dis->dis_out, ", ");
  277. dump_creg(dis, i.cdp.crn);
  278. fprintf(dis->dis_out, ", ");
  279. dump_creg(dis, i.cdp.crm);
  280. if (i.cdp.op2 != 0) {
  281. fprintf(dis->dis_out, ", %d", i.cdp.op2);
  282. }
  283. }
  284. void dump_cdt(ARMDis* dis, ARMInstr i) {
  285. fprintf(dis->dis_out, "%s%s%s\tp%d, ", (i.cdt.ls == 0) ? "stc" : "ldc",
  286. cond[i.generic.cond], (i.cdt.n != 0) ? "l" : "", i.cdt.cpn);
  287. dump_creg(dis, i.cdt.crd);
  288. fprintf(dis->dis_out, ", ");
  289. dump_reg(dis, i.cdt.rn);
  290. if (i.cdt.p == 0) {
  291. fprintf(dis->dis_out, "]");
  292. }
  293. if (i.cdt.offs != 0) {
  294. fprintf(dis->dis_out, ", #%d", i.cdt.offs);
  295. }
  296. if (i.cdt.p != 0) {
  297. fprintf(dis->dis_out, "]%s", (i.cdt.wb != 0) ? "!" : "");
  298. }
  299. }
  300. void dump_crt(ARMDis* dis, ARMInstr i) {
  301. fprintf(dis->dis_out, "%s%s\tp%d, %d, ", (i.crt.ls == 0) ? "mrc" : "mcr",
  302. cond[i.generic.cond], i.crt.cpn, i.crt.op1);
  303. dump_reg(dis, i.crt.rd);
  304. fprintf(dis->dis_out, ", ");
  305. dump_creg(dis, i.crt.crn);
  306. fprintf(dis->dis_out, ", ");
  307. dump_creg(dis, i.crt.crm);
  308. if (i.crt.op2 != 0) {
  309. fprintf(dis->dis_out, ", %d", i.crt.op2);
  310. }
  311. }
  312. void dump_msr(ARMDis* dis, ARMInstr i) {
  313. fprintf(dis->dis_out, "msr%s\t%spsr_, ", cond[i.generic.cond],
  314. (i.msr.all.sel == 0) ? "s" : "c");
  315. if (i.msr.all.type == 0) {
  316. /* reg */
  317. fprintf(dis->dis_out, "%s, ", msr_fld[i.msr.all.fld]);
  318. dump_reg(dis, i.msr.all.rm);
  319. } else {
  320. /* imm */
  321. fprintf(dis->dis_out, "f, #%d", i.msr.op2_imm.imm << i.msr.op2_imm.rot);
  322. }
  323. }
  324. void dump_mrs(ARMDis* dis, ARMInstr i) {
  325. fprintf(dis->dis_out, "mrs%s\t", cond[i.generic.cond]);
  326. dump_reg(dis, i.mrs.rd);
  327. fprintf(dis->dis_out, ", %spsr", (i.mrs.sel == 0) ? "s" : "c");
  328. }
  329. void dump_swi(ARMDis* dis, ARMInstr i) {
  330. fprintf(dis->dis_out, "swi%s\t%d", cond[i.generic.cond], i.swi.num);
  331. }
  332. void dump_clz(ARMDis* dis, ARMInstr i) {
  333. fprintf(dis->dis_out, "clz%s\t", cond[i.generic.cond]);
  334. dump_reg(dis, i.clz.rd);
  335. fprintf(dis->dis_out, ", ");
  336. dump_reg(dis, i.clz.rm);
  337. fprintf(dis->dis_out, "\n");
  338. }
  339. void armdis_decode(ARMDis* dis, cg_segment_t * segment) {
  340. size_t i, offset = 0;
  341. ARMInstr instr;
  342. size_t size;
  343. if (dis == NULL) return;
  344. chk_out(dis);
  345. size = cg_segment_size(segment) / sizeof(arminstr_t);
  346. dis->segment = segment;
  347. for (i=0; i<size; ++i) {
  348. instr.raw = cg_segment_get_u32(segment, offset);
  349. fprintf(dis->dis_out, "%p:\t%08x\t", (void *) offset, instr.raw);
  350. dis->offset = offset;
  351. offset += sizeof(U32);
  352. if ((instr.raw & ARM_BR_MASK) == ARM_BR_TAG) {
  353. dump_br(dis, instr);
  354. } else if ((instr.raw & ARM_SWP_MASK) == ARM_SWP_TAG) {
  355. dump_swp(dis, instr);
  356. } else if ((instr.raw & ARM_MUL_MASK) == ARM_MUL_TAG) {
  357. dump_mul(dis, instr);
  358. } else if ((instr.raw & ARM_CLZ_MASK) == ARM_CLZ_TAG) {
  359. dump_clz(dis, instr);
  360. } else if ((instr.raw & ARM_WXFER_MASK) == ARM_WXFER_TAG) {
  361. dump_wxfer(dis, instr);
  362. } else if ((instr.raw & ARM_HXFER_MASK) == ARM_HXFER_TAG) {
  363. dump_hxfer(dis, instr);
  364. } else if ((instr.raw & ARM_DPI_MASK) == ARM_DPI_TAG) {
  365. dump_dpi(dis, instr);
  366. } else if ((instr.raw & ARM_MRT_MASK) == ARM_MRT_TAG) {
  367. dump_mrt(dis, instr);
  368. } else if ((instr.raw & ARM_CDP_MASK) == ARM_CDP_TAG) {
  369. dump_cdp(dis, instr);
  370. } else if ((instr.raw & ARM_CDT_MASK) == ARM_CDT_TAG) {
  371. dump_cdt(dis, instr);
  372. } else if ((instr.raw & ARM_CRT_MASK) == ARM_CRT_TAG) {
  373. dump_crt(dis, instr);
  374. } else if ((instr.raw & ARM_MSR_MASK) == ARM_MSR_TAG) {
  375. dump_msr(dis, instr);
  376. } else if ((instr.raw & ARM_MRS_MASK) == ARM_MRS_TAG) {
  377. dump_mrs(dis, instr);
  378. } else if ((instr.raw & ARM_SWI_MASK) == ARM_SWI_TAG) {
  379. dump_swi(dis, instr);
  380. } else {
  381. fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", instr.raw);
  382. }
  383. fprintf(dis->dis_out, "\n");
  384. }
  385. }
  386. void armdis_open(ARMDis* dis, const char* dump_name) {
  387. if (dis != NULL && dump_name != NULL) {
  388. armdis_set_output(dis, fopen(dump_name, "w"));
  389. }
  390. }
  391. void armdis_close(ARMDis* dis) {
  392. if (dis->dis_out != NULL && dis->dis_out != stdout && dis->dis_out != stderr) {
  393. fclose(dis->dis_out);
  394. dis->dis_out = NULL;
  395. }
  396. }
  397. void armdis_dump(ARMDis* dis, const char* dump_name, cg_segment_t * segment) {
  398. armdis_open(dis, dump_name);
  399. armdis_decode(dis, segment);
  400. armdis_close(dis);
  401. }
  402. void armdis_init(ARMDis* dis) {
  403. if (dis != NULL) {
  404. /* set to stdout */
  405. armdis_set_output(dis, NULL);
  406. }
  407. }