1 /*
2 * HT Editor
3 * avrdis.cc
4 *
5 * Copyright (C) 2008 Sebastian Biallas (sb@biallas.net)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "endianess.h"
22 #include "avrdis.h"
23 #include "avropc.h"
24 #include "snprintf.h"
25 #include "tools.h"
26
AVRDisassembler()27 AVRDisassembler::AVRDisassembler()
28 {
29 }
30
decode(byte * code,int maxlen,CPU_ADDR addr)31 dis_insn *AVRDisassembler::decode(byte *code, int maxlen, CPU_ADDR addr)
32 {
33 const struct avr_opcode *opcode;
34 const struct avr_opcode *opcode_end;
35 uint32 op;
36
37 if (maxlen < 2) {
38 insn.valid = false;
39 insn.size = maxlen;
40 return &insn;
41 }
42
43 insn.data = createHostInt(code, 2, little_endian);
44
45 if ((insn.data & 0xfe0c) == 0x940c || (insn.data & 0xfc0f) == 0x9000) {
46 insn.size = 4;
47 if (maxlen < 4) {
48 insn.valid = false;
49 insn.size = maxlen;
50 return &insn;
51 }
52 insn.data |= createHostInt(code+2, 2, little_endian) << 16;
53 } else {
54 insn.size = 2;
55 }
56
57 op = insn.data;
58
59 opcode_end = avr_opcodes + avr_num_opcodes;
60
61 for (opcode = avr_opcodes; opcode < opcode_end; opcode++) {
62 const byte *opindex;
63 const struct avr_operand *operand;
64 bool invalid;
65
66 if ((insn.data & opcode->mask) != opcode->opcode) {
67 continue;
68 }
69
70 /* Make two passes over the operands. First see if any of them
71 have extraction functions, and, if they do, make sure the
72 instruction is valid. */
73 invalid = false;
74 for (opindex = opcode->operands; *opindex != 0; opindex++) {
75 operand = avr_operands + *opindex;
76 if (operand->extract) (*operand->extract)(insn.data, &invalid);
77 }
78 if (invalid) continue;
79
80 /* The instruction is valid. */
81 insn.name = opcode->name;
82
83 /* Now extract and print the operands. */
84 int opidx = 0;
85 for (opindex = opcode->operands; *opindex != 0; opindex++) {
86 sint32 value;
87
88 operand = avr_operands + *opindex;
89
90 /* Operands that are marked FAKE are simply ignored. We
91 already made sure that the extract function considered
92 the instruction to be valid. */
93 if ((operand->flags & AVR_OPERAND_FAKE) != 0) continue;
94
95 insn.op[opidx].op = operand;
96 insn.op[opidx].flags = operand->flags;
97 /* Extract the value from the instruction. */
98 if (operand->extract) {
99 value = (*operand->extract)(insn.data, NULL);
100 } else {
101 value = (insn.data >> operand->shift) & ((1 << operand->bits) - 1);
102 value <<= operand->scale;
103 value += operand->add;
104 if ((operand->flags & AVR_OPERAND_SIGNED) != 0 && (value & (1 << (operand->bits + operand->scale - 1))) != 0) {
105 value |= -1 << (operand->bits + operand->scale);
106 }
107 }
108
109 if (operand->flags & (AVR_OPERAND_GPR | AVR_OPERAND_GPR_2)) {
110 insn.op[opidx++].reg = value;
111 } else if (operand->flags & (AVR_OPERAND_IMM | AVR_OPERAND_ABS)) {
112 insn.op[opidx++].imm = value;
113 } else if (operand->flags & AVR_OPERAND_REL) {
114 insn.op[opidx++].imm = addr.addr32.offset + value + 2;
115 } else if (operand->flags & AVR_OPERAND_Yq) {
116 insn.op[opidx++].mem.disp = value;
117 } else if (operand->flags & AVR_OPERAND_Zq) {
118 insn.op[opidx++].mem.disp = value;
119 }
120
121 }
122 insn.ops = opidx;
123
124 /* We have found and printed an instruction; return. */
125 insn.valid = true;
126 return &insn;
127 }
128
129 insn.valid = false;
130 return &insn;
131 }
132
duplicateInsn(dis_insn * disasm_insn)133 dis_insn *AVRDisassembler::duplicateInsn(dis_insn *disasm_insn)
134 {
135 avrdis_insn *insn = ht_malloc(sizeof (avrdis_insn));
136 *insn = *(avrdis_insn *)disasm_insn;
137 return insn;
138 }
139
getOpcodeMetrics(int & min_length,int & max_length,int & min_look_ahead,int & avg_look_ahead,int & addr_align)140 void AVRDisassembler::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align)
141 {
142 min_length = 2;
143 max_length = 4;
144 min_look_ahead = 4;
145 avg_look_ahead = 4;
146 addr_align = 2;
147 }
148
getSize(dis_insn * disasm_insn)149 byte AVRDisassembler::getSize(dis_insn *disasm_insn)
150 {
151 return ((avrdis_insn*)disasm_insn)->size;
152 }
153
getName()154 const char *AVRDisassembler::getName()
155 {
156 return "AVR/Disassembler";
157 }
158
str(dis_insn * disasm_insn,int style)159 const char *AVRDisassembler::str(dis_insn *disasm_insn, int style)
160 {
161 return strf(disasm_insn, style, "");
162 }
163
strf(dis_insn * disasm_insn,int style,const char * format)164 const char *AVRDisassembler::strf(dis_insn *disasm_insn, int style, const char *format)
165 {
166 if (style & DIS_STYLE_HIGHLIGHT) enable_highlighting();
167
168 const char *cs_default = get_cs(e_cs_default);
169 const char *cs_number = get_cs(e_cs_number);
170 const char *cs_symbol = get_cs(e_cs_symbol);
171
172 avrdis_insn *avr_insn = (avrdis_insn *) disasm_insn;
173 if (!avr_insn->valid) {
174 switch (avr_insn->size) {
175 case 1:
176 strcpy(insnstr, "db ?");
177 break;
178 case 2:
179 sprintf(insnstr, "dw %s0x%04x", cs_number, avr_insn->data);
180 break;
181 case 3:
182 strcpy(insnstr, "db ? * 3");
183 break;
184 case 4:
185 sprintf(insnstr, "dd %s0x%08x", cs_number, avr_insn->data);
186 break;
187 default: { /* braces for empty assert */
188 strcpy(insnstr, "?");
189 // assert(0);
190 }
191 }
192 } else {
193 char *is = insnstr+sprintf(insnstr, "%-13s", avr_insn->name);
194
195 bool need_comma = false;
196 bool need_paren = false;
197 for (int opidx = 0; opidx < avr_insn->ops; opidx++) {
198 int flags = avr_insn->op[opidx].flags;
199 if (need_comma) {
200 is += sprintf(is, "%s, ", cs_symbol);
201 need_comma = false;
202 } else {
203 need_comma = true;
204 }
205 if (flags & AVR_OPERAND_GPR) {
206 is += sprintf(is, "%sr%d", cs_default, avr_insn->op[opidx].reg);
207 } else if (flags & AVR_OPERAND_GPR_2) {
208 is += sprintf(is, "%sr%d%s:%sr%d", cs_default, avr_insn->op[opidx].reg, cs_symbol, cs_default, avr_insn->op[opidx].reg+1);
209 } else if (flags & AVR_OPERAND_XYZ_MASK) {
210 int xyz = (flags & AVR_OPERAND_XYZ_MASK) - 1;
211 const char *r[] = {"X", "X+", "-X", "Y", "Y+", "-Y", "Y%s%c%s%d", "Z", "Z+", "-Z", "Z%s%c%s%d"};
212 char buf[100];
213 ht_snprintf(buf, sizeof buf, "%s%s", cs_default, r[xyz]);
214 unsigned q = avr_insn->op[opidx].mem.disp;
215 char c;
216 if (q < 0) {
217 q = -q;
218 c = '-';
219 } else {
220 c = '+';
221 }
222 is += sprintf(is, buf, cs_symbol, c, cs_number, q);
223 } else if (flags & (AVR_OPERAND_ABS | AVR_OPERAND_REL)) {
224 CPU_ADDR caddr;
225 caddr.addr32.offset = uint32(avr_insn->op[opidx].imm);
226 int slen;
227 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
228 if (s) {
229 is += sprintf(is, "%s", cs_default);
230 memcpy(is, s, slen);
231 is[slen] = 0;
232 is += slen;
233 } else {
234 is += ht_snprintf(is, 100, "%s0x%x", cs_number, avr_insn->op[opidx].imm);
235 }
236 } else if ((flags & AVR_OPERAND_IMM) != 0) {
237 is += sprintf(is, "%s%d", cs_number, (int)avr_insn->op[opidx].imm);
238 }
239 #if 0
240 } else if (flags & (PPC_OPERAND_RELATIVE | )) {
241 CPU_ADDR caddr;
242 if (mode == PPC_MODE_32) {
243 caddr.addr32.offset = (uint32)ppc_insn->op[opidx].mem.disp;
244 } else {
245 caddr.flat64.addr = ppc_insn->op[opidx].mem.disp;
246 }
247 int slen;
248 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
249 if (s) {
250 is += sprintf(is, "%s", cs_default);
251 memcpy(is, s, slen);
252 is[slen] = 0;
253 is += slen;
254 } else {
255 is += ht_snprintf(is, 100, "%s0x%qx", cs_number, ppc_insn->op[opidx].rel.mem);
256 }
257 } else if ((flags & PPC_OPERAND_ABSOLUTE) != 0) {
258 is += ht_snprintf(is, 100, "%s0x%qx", cs_number, ppc_insn->op[opidx].abs.mem);
259 } else if ((flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
260 is += ht_snprintf(is, 100, "%s%qd", cs_number, ppc_insn->op[opidx].imm);
261 } else if (ppc_insn->op[opidx].op->bits == 3) {
262 is += sprintf(is, "%scr%d", cs_default, ppc_insn->op[opidx].creg);
263 } else {
264 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
265 int cr;
266 int cc;
267 cr = ppc_insn->op[opidx].creg >> 2;
268 if (cr != 0) is += sprintf(is, "%s4%s*%scr%d", cs_number, cs_symbol, cs_default, cr);
269 cc = ppc_insn->op[opidx].creg & 3;
270 if (cc != 0) {
271 if (cr != 0) is += sprintf(is, "%s+", cs_symbol);
272 is += sprintf(is, "%s%s", cs_default, cbnames[cc]);
273 }
274 }
275 #endif
276 }
277 }
278 disable_highlighting();
279 return insnstr;
280 }
281
getObjectID() const282 ObjectID AVRDisassembler::getObjectID() const
283 {
284 return ATOM_DISASM_AVR;
285 }
286
validInsn(dis_insn * disasm_insn)287 bool AVRDisassembler::validInsn(dis_insn *disasm_insn)
288 {
289 return ((avrdis_insn*)disasm_insn)->valid;
290 }
291