/[pearpc]/src/debug/ppcdis.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/debug/ppcdis.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 9200 byte(s)
import upstream CVS
1 /*
2 * HT Editor
3 * ppcdis.cc
4 *
5 * Copyright (C) 1999-2002 Sebastian Biallas (sb@web-productions.de)
6 * Copyright 1994 Free Software Foundation, Inc.
7 * Written by Ian Lance Taylor, Cygnus Support
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <cstdlib>
24 #include <cstring>
25
26 #include "tools/endianess.h"
27 #include "tools/snprintf.h"
28 #include "ppcdis.h"
29 #include "ppcopc.h"
30
31 PPCDisassembler::PPCDisassembler()
32 {
33 }
34
35 dis_insn *PPCDisassembler::decode(const byte *code, int maxlen, CPU_ADDR addr)
36 {
37 const struct powerpc_opcode *opcode;
38 const struct powerpc_opcode *opcode_end;
39 uint32 op;
40 int dialect = -1;
41
42 insn.data = createHostInt(code, 4, little_endian);
43
44 if (maxlen<4) {
45 insn.valid = false;
46 insn.size = maxlen;
47 return &insn;
48 }
49
50 insn.size = 4;
51
52 /* Get the major opcode of the instruction. */
53 op = PPC_OP(insn.data);
54
55 /* Find the first match in the opcode table. We could speed this up
56 a bit by doing a binary search on the major opcode. */
57 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
58
59 for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) {
60 uint32 table_op;
61 const byte *opindex;
62 const struct powerpc_operand *operand;
63 bool invalid;
64 bool need_comma;
65 bool need_paren;
66
67 table_op = PPC_OP (opcode->opcode);
68 if (op < table_op) break;
69 if (op > table_op) continue;
70
71 if ((insn.data & opcode->mask) != opcode->opcode || (opcode->flags & dialect) == 0) {
72 continue;
73 }
74
75 /* Make two passes over the operands. First see if any of them
76 have extraction functions, and, if they do, make sure the
77 instruction is valid. */
78 invalid = false;
79 for (opindex = opcode->operands; *opindex != 0; opindex++) {
80 operand = powerpc_operands + *opindex;
81 if (operand->extract) (*operand->extract)(insn.data, &invalid);
82 }
83 if (invalid) continue;
84
85 /* The instruction is valid. */
86 // fprintf(out, "%s", opcode->name);
87 insn.name = opcode->name;
88 // if (opcode->operands[0] != 0) fprintf(out, "\t");
89
90 /* Now extract and print the operands. */
91 need_comma = false;
92 need_paren = false;
93 int opidx = 0;
94 for (opindex = opcode->operands; *opindex != 0; opindex++) {
95 uint32 value;
96
97 operand = powerpc_operands + *opindex;
98
99 /* Operands that are marked FAKE are simply ignored. We
100 already made sure that the extract function considered
101 the instruction to be valid. */
102 if ((operand->flags & PPC_OPERAND_FAKE) != 0) continue;
103
104 insn.op[opidx].op = operand;
105 insn.op[opidx].flags = operand->flags;
106 /* Extract the value from the instruction. */
107 if (operand->extract) {
108 value = (*operand->extract)(insn.data, NULL);
109 } else {
110 value = (insn.data >> operand->shift) & ((1 << operand->bits) - 1);
111 if ((operand->flags & PPC_OPERAND_SIGNED) != 0 && (value & (1 << (operand->bits - 1))) != 0) {
112 value -= 1 << operand->bits;
113 }
114 }
115
116 /* If the operand is optional, and the value is zero, don't
117 print anything. */
118 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 && (operand->flags & PPC_OPERAND_NEXT) == 0 && value == 0) {
119 insn.op[opidx++].imm = 0;
120 continue;
121 }
122
123 if (need_comma) {
124 // fprintf(out, ", ");
125 need_comma = false;
126 }
127
128 /* Print the operand as directed by the flags. */
129 if ((operand->flags & PPC_OPERAND_GPR) != 0) {
130 insn.op[opidx++].reg = value;
131 } else if ((operand->flags & PPC_OPERAND_FPR) != 0) {
132 insn.op[opidx++].freg = value;
133 } else if ((operand->flags & PPC_OPERAND_VR) != 0) {
134 insn.op[opidx++].vreg = value;
135 } else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) {
136 insn.op[opidx++].rel.mem = addr.addr32.offset + value;
137 } else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) {
138 insn.op[opidx++].abs.mem = value;
139 } else if ((operand->flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
140 insn.op[opidx++].imm = value;
141 } else {
142 insn.op[opidx++].creg = value;
143 if (operand->bits == 3) {
144 // fprintf(out, "cr%d", value);
145 } else {
146
147 // static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
148 int cr;
149 int cc;
150 cr = value >> 2;
151 // if (cr != 0) fprintf(out, "4*cr%d", cr);
152 cc = value & 3;
153 if (cc != 0) {
154 // if (cr != 0) fprintf(out, "+");
155 // fprintf(out, "%s", cbnames[cc]);
156 }
157 }
158 }
159
160 if (need_paren) {
161 // fprintf(out, ")");
162 need_paren = false;
163 }
164
165 if ((operand->flags & PPC_OPERAND_PARENS) == 0) {
166 need_comma = true;
167 } else {
168 // fprintf(out, "(");
169 need_paren = true;
170 }
171 }
172 insn.ops = opidx;
173
174 /* We have found and printed an instruction; return. */
175 insn.valid = true;
176 return &insn;
177 }
178
179 insn.valid = false;
180 return &insn;
181 }
182
183 dis_insn *PPCDisassembler::duplicateInsn(dis_insn *disasm_insn)
184 {
185 ppcdis_insn *insn = (ppcdis_insn *)malloc(sizeof (ppcdis_insn));
186 *insn = *(ppcdis_insn *)disasm_insn;
187 return insn;
188 }
189
190 void PPCDisassembler::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align)
191 {
192 min_length = max_length = min_look_ahead = avg_look_ahead = addr_align = 4;
193 }
194
195 byte PPCDisassembler::getSize(dis_insn *disasm_insn)
196 {
197 return ((ppcdis_insn*)disasm_insn)->size;
198 }
199
200 char *PPCDisassembler::getName()
201 {
202 return "PPC/Disassembler";
203 }
204
205 char *PPCDisassembler::str(dis_insn *disasm_insn, int style)
206 {
207 return strf(disasm_insn, style, "");
208 }
209
210 char *PPCDisassembler::strf(dis_insn *disasm_insn, int style, char *format)
211 {
212 if (style & DIS_STYLE_HIGHLIGHT) enable_highlighting();
213
214 const char *cs_default = get_cs(e_cs_default);
215 const char *cs_number = get_cs(e_cs_number);
216 const char *cs_symbol = get_cs(e_cs_symbol);
217
218 ppcdis_insn *ppc_insn = (ppcdis_insn *) disasm_insn;
219 if (!ppc_insn->valid) {
220 switch (ppc_insn->size) {
221 case 1:
222 strcpy(insnstr, "db ?");
223 break;
224 case 2:
225 strcpy(insnstr, "dw ?");
226 break;
227 case 3:
228 strcpy(insnstr, "db ? * 3");
229 break;
230 case 4:
231 ht_snprintf(insnstr, sizeof insnstr, "dd %s0x%08x", cs_number, ppc_insn->data);
232 break;
233 default: { /* braces for empty assert */
234 }
235 }
236 } else {
237 char *is = insnstr+sprintf(insnstr, "%-10s", ppc_insn->name);
238 int dialect=-1;
239
240 bool need_comma = false;
241 bool need_paren = false;
242 for (int opidx = 0; opidx < ppc_insn->ops; opidx++) {
243 int flags = ppc_insn->op[opidx].flags;
244 /* if ((flags & PPC_OPERAND_OPTIONAL) != 0 && (flags & PPC_OPERAND_NEXT) == 0 && ppc_insn->op[opidx].imm == 0) {
245 continue;
246 }*/
247 if (need_comma) {
248 is += sprintf(is, "%s, ", cs_symbol);
249 need_comma = false;
250 }
251 if ((flags & PPC_OPERAND_GPR) != 0) {
252 is += sprintf(is, "%sr%d", cs_default, ppc_insn->op[opidx].reg);
253 } else if ((flags & PPC_OPERAND_FPR) != 0) {
254 is += sprintf(is, "%sf%d", cs_default, ppc_insn->op[opidx].freg);
255 } else if ((flags & PPC_OPERAND_VR) != 0) {
256 is += sprintf(is, "%svr%d", cs_default, ppc_insn->op[opidx].vreg);
257 } else if ((flags & PPC_OPERAND_RELATIVE) != 0) {
258 CPU_ADDR caddr;
259 caddr.addr32.offset = (uint32)ppc_insn->op[opidx].mem.disp;
260 int slen;
261 char *s = (addr_sym_func) ? addr_sym_func(caddr, &slen, addr_sym_func_context) : 0;
262 if (s) {
263 is += sprintf(is, "%s", cs_default);
264 memmove(is, s, slen);
265 is[slen] = 0;
266 is += slen;
267 } else {
268 is += sprintf(is, "%s0x%x", cs_number, ppc_insn->op[opidx].rel.mem);
269 }
270 } else if ((flags & PPC_OPERAND_ABSOLUTE) != 0) {
271 is += sprintf(is, "%s0x%x", cs_number, ppc_insn->op[opidx].abs.mem);
272 } else if ((flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) {
273 is += sprintf(is, "%s%d", cs_number, ppc_insn->op[opidx].imm);
274 } else if (ppc_insn->op[opidx].op->bits == 3) {
275 is += sprintf(is, "%scr%d", cs_default, ppc_insn->op[opidx].creg);
276 } else {
277 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
278 int cr;
279 int cc;
280 cr = ppc_insn->op[opidx].creg >> 2;
281 if (cr != 0) is += sprintf(is, "%s4%s*%scr%d", cs_number, cs_symbol, cs_default, cr);
282 cc = ppc_insn->op[opidx].creg & 3;
283 if (cc != 0) {
284 if (cr != 0) is += sprintf(is, "%s+", cs_symbol);
285 is += sprintf(is, "%s%s", cs_default, cbnames[cc]);
286 }
287 }
288
289 if (need_paren) {
290 is += sprintf(is, "%s)", cs_symbol);
291 need_paren = false;
292 }
293
294 if ((flags & PPC_OPERAND_PARENS) == 0) {
295 need_comma = true;
296 } else {
297 is += sprintf(is, "%s(", cs_symbol);
298 need_paren = true;
299 }
300 }
301 }
302 disable_highlighting();
303 return insnstr;
304 }
305
306 ObjectID PPCDisassembler::getObjectID() const
307 {
308 return 0;
309 }
310
311 bool PPCDisassembler::validInsn(dis_insn *disasm_insn)
312 {
313 return ((ppcdis_insn*)disasm_insn)->valid;
314 }
315
316

  ViewVC Help
Powered by ViewVC 1.1.26