PageRenderTime 540ms CodeModel.GetById 172ms app.highlight 161ms RepoModel.GetById 202ms app.codeStats 0ms

/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
 28
 29#include <stdarg.h>
 30
 31#include "arm-dis.h"
 32#include "arm-codegen.h"
 33
 34
 35static const ARMDis* gdisasm = NULL;
 36
 37static const int use_reg_alias = 1;
 38
 39const static char* cond[] = {
 40	"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
 41	"hi", "ls", "ge", "lt", "gt", "le", "", "nv"
 42};
 43
 44const static char* ops[] = {
 45	"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
 46	"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn"
 47};
 48
 49const static char* shift_types[] = {"lsl", "lsr", "asr", "ror"};
 50
 51const static char* mul_ops[] = {
 52	"mul", "mla", "?", "?", "umull", "umlal", "smull", "smlal"
 53};
 54
 55const static char* reg_alias[] = {
 56	"a1", "a2", "a3", "a4",
 57	"r4", "r5", "r6", "r7", "r8", "r9", "r10",
 58	"fp", "ip", "sp", "lr", "pc"
 59};
 60
 61const static char* msr_fld[] = {"f", "c", "x", "?", "s"};
 62
 63
 64/* private functions prototypes (to keep compiler happy) */
 65void chk_out(ARMDis* dis);
 66void dump_reg(ARMDis* dis, int reg);
 67void dump_creg(ARMDis* dis, int creg);
 68void dump_reglist(ARMDis* dis, int reg_list);
 69void init_gdisasm(void);
 70
 71void dump_br(ARMDis* dis, ARMInstr i);
 72void dump_cdp(ARMDis* dis, ARMInstr i);
 73void dump_cdt(ARMDis* dis, ARMInstr i);
 74void dump_crt(ARMDis* dis, ARMInstr i);
 75void dump_dpi(ARMDis* dis, ARMInstr i);
 76void dump_hxfer(ARMDis* dis, ARMInstr i);
 77void dump_mrs(ARMDis* dis, ARMInstr i);
 78void dump_mrt(ARMDis* dis, ARMInstr i);
 79void dump_msr(ARMDis* dis, ARMInstr i);
 80void dump_mul(ARMDis* dis, ARMInstr i);
 81void dump_swi(ARMDis* dis, ARMInstr i);
 82void dump_swp(ARMDis* dis, ARMInstr i);
 83void dump_wxfer(ARMDis* dis, ARMInstr i);
 84void dump_clz(ARMDis* dis, ARMInstr i);
 85
 86
 87/*
 88void out(ARMDis* dis, const char* format, ...) {
 89	va_list arglist;
 90	va_start(arglist, format);
 91	fprintf(dis->dis_out, format, arglist);
 92	va_end(arglist);
 93}
 94*/
 95
 96
 97void chk_out(ARMDis* dis) {
 98	if (dis != NULL && dis->dis_out == NULL) dis->dis_out = stdout;
 99}
100
101
102void armdis_set_output(ARMDis* dis, FILE* f) {
103	if (dis != NULL) {
104		dis->dis_out = f;
105		chk_out(dis);
106	}
107}
108
109FILE* armdis_get_output(ARMDis* dis) {
110	return (dis != NULL ? dis->dis_out : NULL);
111}
112
113
114
115
116void dump_reg(ARMDis* dis, int reg) {
117	reg &= 0xF;
118	if (!use_reg_alias || (reg > 3 && reg < 11)) {
119		fprintf(dis->dis_out, "r%d", reg);
120	} else {
121		fprintf(dis->dis_out, reg_alias[reg]);
122	}
123}
124
125void dump_creg(ARMDis* dis, int creg) {
126	if (dis != NULL) {
127		creg &= 0xF;
128		fprintf(dis->dis_out, "c%d", creg);
129	}
130}
131
132void dump_reglist(ARMDis* dis, int reg_list) {
133	int i = 0, j, n = 0;
134	int m1 = 1, m2, rn;
135	while (i < 16) {
136		if ((reg_list & m1) != 0) {
137			if (n != 0) fprintf(dis->dis_out, ", ");
138			n++;
139			dump_reg(dis, i);
140			for (j = i+1, rn = 0, m2 = m1<<1; j < 16; ++j, m2<<=1) {
141				if ((reg_list & m2) != 0) ++rn;
142				else break;
143			}
144			i+=rn;
145			if (rn > 1) {
146				fprintf(dis->dis_out, "-");
147				dump_reg(dis, i);
148			} else if (rn == 1) {
149				fprintf(dis->dis_out, ", ");
150				dump_reg(dis, i);
151			}
152			m1<<=(rn+1);
153			i++;
154		} else {
155			++i;
156			m1<<=1;
157		}
158	}
159}
160
161
162void dump_br(ARMDis* dis, ARMInstr i) {
163	fprintf(dis->dis_out, "b%s%s\t%x\t; %x -> %x",
164	    (i.br.link == 1) ? "l" : "",
165	    cond[i.br.cond], i.br.offset, dis->offset, (int)dis->offset + 4*2 + ((int)(i.br.offset << 8) >> 6));
166}
167
168
169void dump_dpi(ARMDis* dis, ARMInstr i) {
170	fprintf(dis->dis_out, "%s%s", ops[i.dpi.all.opcode], cond[i.dpi.all.cond]);
171
172	if ((i.dpi.all.opcode < ARMOP_TST || i.dpi.all.opcode > ARMOP_CMN) && (i.dpi.all.s != 0)) {
173		fprintf(dis->dis_out, "s");
174	}
175
176	fprintf(dis->dis_out, "\t");
177
178	if ((i.dpi.all.opcode < ARMOP_TST) || (i.dpi.all.opcode > ARMOP_CMN)) {
179		/* for comparison operations Rd is ignored */
180		dump_reg(dis, i.dpi.all.rd);
181		fprintf(dis->dis_out, ", ");
182	}
183
184	if ((i.dpi.all.opcode != ARMOP_MOV) && (i.dpi.all.opcode != ARMOP_MVN)) {
185		/* for MOV/MVN Rn is ignored */
186		dump_reg(dis, i.dpi.all.rn);
187		fprintf(dis->dis_out, ", ");
188	}
189
190	if (i.dpi.all.type == 1) {
191		/* immediate */
192		if (i.dpi.op2_imm.rot != 0) {
193			fprintf(dis->dis_out, "#%d, %d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.rot << 1,
194			        ARM_SCALE(i.dpi.op2_imm.imm, (i.dpi.op2_imm.rot << 1)) );
195		} else {
196			fprintf(dis->dis_out, "#%d\t; 0x%x", i.dpi.op2_imm.imm, i.dpi.op2_imm.imm);
197		}
198	} else {
199		/* reg-reg */
200		if (i.dpi.op2_reg.tag == 0) {
201			/* op2 is reg shift by imm */
202			dump_reg(dis, i.dpi.op2_reg_imm.r2.rm);
203			if (i.dpi.op2_reg_imm.imm.shift != 0) {
204				fprintf(dis->dis_out, " %s #%d", shift_types[i.dpi.op2_reg_imm.r2.type], i.dpi.op2_reg_imm.imm.shift);
205			}
206		} else {
207			/* op2 is reg shift by reg */
208			dump_reg(dis, i.dpi.op2_reg_reg.r2.rm);
209			fprintf(dis->dis_out, " %s ", shift_types[i.dpi.op2_reg_reg.r2.type]);
210			dump_reg(dis, i.dpi.op2_reg_reg.reg.rs);
211		}
212
213	}
214}
215
216void dump_wxfer(ARMDis* dis, ARMInstr i) {
217	fprintf(dis->dis_out, "%s%s%s%s\t",
218		(i.wxfer.all.ls == 0) ? "str" : "ldr",
219		cond[i.generic.cond],
220		(i.wxfer.all.b == 0) ? "" : "b",
221		(i.wxfer.all.ls != 0 && i.wxfer.all.wb != 0) ? "t" : "");
222	dump_reg(dis, i.wxfer.all.rd);
223	fprintf(dis->dis_out, ", [");
224	dump_reg(dis, i.wxfer.all.rn);
225	fprintf(dis->dis_out, "%s, ", (i.wxfer.all.p == 0) ? "]" : "");
226
227	if (i.wxfer.all.type == 0) { /* imm */
228		fprintf(dis->dis_out, "#%s%d", (i.wxfer.all.u == 0) ? "-" : "", i.wxfer.all.op2_imm);
229	} else {
230		dump_reg(dis, i.wxfer.op2_reg_imm.r2.rm);
231		if (i.wxfer.op2_reg_imm.imm.shift != 0) {
232			fprintf(dis->dis_out, " %s #%d", shift_types[i.wxfer.op2_reg_imm.r2.type], i.wxfer.op2_reg_imm.imm.shift);
233		}
234	}
235
236	if (i.wxfer.all.p != 0) {
237		/* close pre-index instr, also check for write-back */
238		fprintf(dis->dis_out, "]%s", (i.wxfer.all.wb != 0) ? "!" : "");
239	}
240}
241
242void dump_hxfer(ARMDis* dis, ARMInstr i) {
243	fprintf(dis->dis_out, "%s%s%s%s\t",
244		(i.hxfer.ls == 0) ? "str" : "ldr",
245		cond[i.generic.cond],
246		(i.hxfer.s != 0) ? "s" : "",
247		(i.hxfer.h != 0) ? "h" : "b");
248	dump_reg(dis, i.hxfer.rd);
249	fprintf(dis->dis_out, ", [");
250	dump_reg(dis, i.hxfer.rn);
251	fprintf(dis->dis_out, "%s, ", (i.hxfer.p == 0) ? "]" : "");
252
253	if (i.hxfer.type != 0) { /* imm */
254		fprintf(dis->dis_out, "#%s%d", (i.hxfer.u == 0) ? "-" : "", (i.hxfer.imm_hi << 4) | i.hxfer.rm);
255	} else {
256		dump_reg(dis, i.hxfer.rm);
257	}
258
259	if (i.hxfer.p != 0) {
260		/* close pre-index instr, also check for write-back */
261		fprintf(dis->dis_out, "]%s", (i.hxfer.wb != 0) ? "!" : "");
262	}
263}
264
265
266void dump_mrt(ARMDis* dis, ARMInstr i) {
267	fprintf(dis->dis_out, "%s%s%s%s\t", (i.mrt.ls == 0) ? "stm" : "ldm", cond[i.mrt.cond],
268	        (i.mrt.u == 0) ? "d" : "i", (i.mrt.p == 0) ? "a" : "b");
269	dump_reg(dis, i.mrt.rn);
270	fprintf(dis->dis_out, "%s, {", (i.mrt.wb != 0) ? "!" : "");
271	dump_reglist(dis, i.mrt.reg_list);
272	fprintf(dis->dis_out, "}");
273}
274
275
276void dump_swp(ARMDis* dis, ARMInstr i) {
277	fprintf(dis->dis_out, "swp%s%s ", cond[i.swp.cond], (i.swp.b != 0) ? "b" : "");
278	dump_reg(dis, i.swp.rd);
279	fprintf(dis->dis_out, ", ");
280	dump_reg(dis, i.swp.rm);
281	fprintf(dis->dis_out, ", [");
282	dump_reg(dis, i.swp.rn);
283	fprintf(dis->dis_out, "]");
284}
285
286
287void dump_mul(ARMDis* dis, ARMInstr i) {
288	fprintf(dis->dis_out, "%s%s%s\t", mul_ops[i.mul.opcode], cond[i.mul.cond], (i.mul.s != 0) ? "s" : "");
289	switch (i.mul.opcode) {
290	case ARMOP_MUL:
291		dump_reg(dis, i.mul.rd);
292		fprintf(dis->dis_out, ", ");
293		dump_reg(dis, i.mul.rm);
294		fprintf(dis->dis_out, ", ");
295		dump_reg(dis, i.mul.rs);
296		break;
297	case ARMOP_MLA:
298		dump_reg(dis, i.mul.rd);
299		fprintf(dis->dis_out, ", ");
300		dump_reg(dis, i.mul.rm);
301		fprintf(dis->dis_out, ", ");
302		dump_reg(dis, i.mul.rs);
303		fprintf(dis->dis_out, ", ");
304		dump_reg(dis, i.mul.rn);
305		break;
306	case ARMOP_UMULL:
307	case ARMOP_UMLAL:
308	case ARMOP_SMULL:
309	case ARMOP_SMLAL:
310		dump_reg(dis, i.mul.rd);
311		fprintf(dis->dis_out, ", ");
312		dump_reg(dis, i.mul.rn);
313		fprintf(dis->dis_out, ", ");
314		dump_reg(dis, i.mul.rm);
315		fprintf(dis->dis_out, ", ");
316		dump_reg(dis, i.mul.rs);
317		break;
318	default:
319		fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", i.raw);
320		break;
321	}
322}
323
324
325void dump_cdp(ARMDis* dis, ARMInstr i) {
326	fprintf(dis->dis_out, "cdp%s\tp%d, %d, ", cond[i.generic.cond], i.cdp.cpn, i.cdp.op);
327	dump_creg(dis, i.cdp.crd);
328	fprintf(dis->dis_out, ", ");
329	dump_creg(dis, i.cdp.crn);
330	fprintf(dis->dis_out, ", ");
331	dump_creg(dis, i.cdp.crm);
332
333	if (i.cdp.op2 != 0) {
334		fprintf(dis->dis_out, ", %d", i.cdp.op2);
335	}
336}
337
338
339void dump_cdt(ARMDis* dis, ARMInstr i) {
340	fprintf(dis->dis_out, "%s%s%s\tp%d, ", (i.cdt.ls == 0) ? "stc" : "ldc",
341	        cond[i.generic.cond], (i.cdt.n != 0) ? "l" : "", i.cdt.cpn);
342	dump_creg(dis, i.cdt.crd);
343	fprintf(dis->dis_out, ", ");
344	dump_reg(dis, i.cdt.rn);
345
346	if (i.cdt.p == 0) {
347		fprintf(dis->dis_out, "]");
348	}
349
350	if (i.cdt.offs != 0) {
351		fprintf(dis->dis_out, ", #%d", i.cdt.offs);
352	}
353
354	if (i.cdt.p != 0) {
355		fprintf(dis->dis_out, "]%s", (i.cdt.wb != 0) ? "!" : "");
356	}
357}
358
359
360void dump_crt(ARMDis* dis, ARMInstr i) {
361	fprintf(dis->dis_out, "%s%s\tp%d, %d, ", (i.crt.ls == 0) ? "mrc" : "mcr",
362	        cond[i.generic.cond], i.crt.cpn, i.crt.op1);
363	dump_reg(dis, i.crt.rd);
364	fprintf(dis->dis_out, ", ");
365	dump_creg(dis, i.crt.crn);
366	fprintf(dis->dis_out, ", ");
367	dump_creg(dis, i.crt.crm);
368
369	if (i.crt.op2 != 0) {
370		fprintf(dis->dis_out, ", %d", i.crt.op2);
371	}
372}
373
374
375void dump_msr(ARMDis* dis, ARMInstr i) {
376	fprintf(dis->dis_out, "msr%s\t%spsr_, ", cond[i.generic.cond],
377	        (i.msr.all.sel == 0) ? "s" : "c");
378	if (i.msr.all.type == 0) {
379		/* reg */
380		fprintf(dis->dis_out, "%s, ", msr_fld[i.msr.all.fld]);
381		dump_reg(dis, i.msr.all.rm);
382	} else {
383		/* imm */
384		fprintf(dis->dis_out, "f, #%d", i.msr.op2_imm.imm << i.msr.op2_imm.rot);
385	}
386}
387
388
389void dump_mrs(ARMDis* dis, ARMInstr i) {
390	fprintf(dis->dis_out, "mrs%s\t", cond[i.generic.cond]);
391	dump_reg(dis, i.mrs.rd);
392	fprintf(dis->dis_out, ", %spsr", (i.mrs.sel == 0) ? "s" : "c");
393}
394
395
396void dump_swi(ARMDis* dis, ARMInstr i) {
397	fprintf(dis->dis_out, "swi%s\t%d", cond[i.generic.cond], i.swi.num);
398}
399
400
401void dump_clz(ARMDis* dis, ARMInstr i) {
402	fprintf(dis->dis_out, "clz%s\t", cond[i.generic.cond]);
403	dump_reg(dis, i.clz.rd);
404	fprintf(dis->dis_out, ", ");
405	dump_reg(dis, i.clz.rm);
406	fprintf(dis->dis_out, "\n");
407}
408
409
410
411void armdis_decode(ARMDis* dis, cg_segment_t * segment) {
412	size_t i, offset = 0;
413	ARMInstr instr;
414	size_t size;
415
416	if (dis == NULL) return;
417
418	chk_out(dis);
419
420	size = cg_segment_size(segment) / sizeof(arminstr_t);
421	dis->segment = segment;
422
423	for (i=0; i<size; ++i) {
424		instr.raw = cg_segment_get_u32(segment, offset);
425		fprintf(dis->dis_out, "%p:\t%08x\t", (void *) offset, instr.raw);
426		dis->offset = offset;
427		offset += sizeof(U32);
428
429		if ((instr.raw & ARM_BR_MASK) == ARM_BR_TAG) {
430			dump_br(dis, instr);
431		} else if ((instr.raw & ARM_SWP_MASK) == ARM_SWP_TAG) {
432			dump_swp(dis, instr);
433		} else if ((instr.raw & ARM_MUL_MASK) == ARM_MUL_TAG) {
434			dump_mul(dis, instr);
435		} else if ((instr.raw & ARM_CLZ_MASK) == ARM_CLZ_TAG) {
436			dump_clz(dis, instr);
437		} else if ((instr.raw & ARM_WXFER_MASK) == ARM_WXFER_TAG) {
438			dump_wxfer(dis, instr);
439		} else if ((instr.raw & ARM_HXFER_MASK) == ARM_HXFER_TAG) {
440			dump_hxfer(dis, instr);
441		} else if ((instr.raw & ARM_DPI_MASK) == ARM_DPI_TAG) {
442			dump_dpi(dis, instr);
443		} else if ((instr.raw & ARM_MRT_MASK) == ARM_MRT_TAG) {
444			dump_mrt(dis, instr);
445		} else if ((instr.raw & ARM_CDP_MASK) == ARM_CDP_TAG) {
446			dump_cdp(dis, instr);
447		} else if ((instr.raw & ARM_CDT_MASK) == ARM_CDT_TAG) {
448			dump_cdt(dis, instr);
449		} else if ((instr.raw & ARM_CRT_MASK) == ARM_CRT_TAG) {
450			dump_crt(dis, instr);
451		} else if ((instr.raw & ARM_MSR_MASK) == ARM_MSR_TAG) {
452			dump_msr(dis, instr);
453		} else if ((instr.raw & ARM_MRS_MASK) == ARM_MRS_TAG) {
454			dump_mrs(dis, instr);
455		} else if ((instr.raw & ARM_SWI_MASK) == ARM_SWI_TAG) {
456			dump_swi(dis, instr);
457		} else {
458			fprintf(dis->dis_out, "DCD 0x%x\t; <unknown>", instr.raw);
459		}
460
461		fprintf(dis->dis_out, "\n");
462	}
463}
464
465
466void armdis_open(ARMDis* dis, const char* dump_name) {
467	if (dis != NULL && dump_name != NULL) {
468		armdis_set_output(dis, fopen(dump_name, "w"));
469	}
470}
471
472
473void armdis_close(ARMDis* dis) {
474	if (dis->dis_out != NULL && dis->dis_out != stdout && dis->dis_out != stderr) {
475		fclose(dis->dis_out);
476		dis->dis_out = NULL;
477	}
478}
479
480
481void armdis_dump(ARMDis* dis, const char* dump_name, cg_segment_t * segment) {
482	armdis_open(dis, dump_name);
483	armdis_decode(dis, segment);
484	armdis_close(dis);
485}
486
487
488void armdis_init(ARMDis* dis) {
489	if (dis != NULL) {
490		/* set to stdout */
491		armdis_set_output(dis, NULL);
492	}
493}
494