1 #include <lib9.h>
2
3 typedef struct Instr Instr;
4 struct Instr
5 {
6 ulong w;
7 ulong addr;
8 uchar op; /* super opcode */
9
10 uchar cond; /* bits 28-31 */
11 uchar store; /* bit 20 */
12
13 uchar rd; /* bits 12-15 */
14 uchar rn; /* bits 16-19 */
15 uchar rs; /* bits 0-11 */
16
17 long imm; /* rotated imm */
18 char* curr; /* fill point in buffer */
19 char* end; /* end of buffer */
20 char* err; /* error message */
21 };
22
23 typedef struct Opcode Opcode;
24 struct Opcode
25 {
26 char* o;
27 void (*f)(Opcode*, Instr*);
28 char* a;
29 };
30
31 static void format(char*, Instr*, char*);
32 static int arminst(ulong, char, char*, int);
33 static int armdas(ulong, char*, int);
34
35 static
36 char* cond[16] =
37 {
38 "EQ", "NE", "CS", "CC",
39 "MI", "PL", "VS", "VC",
40 "HI", "LS", "GE", "LT",
41 "GT", "LE", 0, "NV"
42 };
43
44 static
45 char* shtype[4] =
46 {
47 "<<", ">>", "->", "@>"
48 };
49
50 static int
get4(ulong addr,long * v)51 get4(ulong addr, long *v)
52 {
53 *v = *(ulong*)addr;
54 return 1;
55 }
56
57 static char *
_hexify(char * buf,ulong p,int zeros)58 _hexify(char *buf, ulong p, int zeros)
59 {
60 ulong d;
61
62 d = p/16;
63 if(d)
64 buf = _hexify(buf, d, zeros-1);
65 else
66 while(zeros--)
67 *buf++ = '0';
68 *buf++ = "0123456789abcdef"[p&0x0f];
69 return buf;
70 }
71
72 int
armclass(long w)73 armclass(long w)
74 {
75 int op;
76
77 op = (w >> 25) & 0x7;
78 switch(op) {
79 case 0: /* data processing r,r,r */
80 op = ((w >> 4) & 0xf);
81 if(op == 0x9) {
82 op = 48+16; /* mul */
83 if(w & (1<<24)) {
84 op += 2;
85 if(w & (1<<22))
86 op++; /* swap */
87 break;
88 }
89 if(w & (1<<21))
90 op++; /* mla */
91 break;
92 }
93 op = (w >> 21) & 0xf;
94 if(w & (1<<4))
95 op += 32;
96 else
97 if(w & (31<<7))
98 op += 16;
99 break;
100 case 1: /* data processing i,r,r */
101 op = (48) + ((w >> 21) & 0xf);
102 break;
103 case 2: /* load/store byte/word i(r) */
104 op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
105 break;
106 case 3: /* load/store byte/word (r)(r) */
107 op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
108 break;
109 case 4: /* block data transfer (r)(r) */
110 op = (48+20+4+4) + ((w >> 20) & 0x1);
111 break;
112 case 5: /* branch / branch link */
113 op = (48+20+4+4+2) + ((w >> 24) & 0x1);
114 break;
115 case 7: /* coprocessor crap */
116 op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
117 break;
118 default:
119 op = (48+20+4+4+2+2+4);
120 break;
121 }
122 return op;
123 }
124
125 static int
decode(ulong pc,Instr * i)126 decode(ulong pc, Instr *i)
127 {
128 long w;
129
130 get4(pc, &w);
131 i->w = w;
132 i->addr = pc;
133 i->cond = (w >> 28) & 0xF;
134 i->op = armclass(w);
135 return 1;
136 }
137
138 static void
bprint(Instr * i,char * fmt,...)139 bprint(Instr *i, char *fmt, ...)
140 {
141 va_list arg;
142
143 va_start(arg, fmt);
144 i->curr = vseprint(i->curr, i->end, fmt, arg);
145 va_end(arg);
146 }
147
148 static void
armdps(Opcode * o,Instr * i)149 armdps(Opcode *o, Instr *i)
150 {
151 i->store = (i->w >> 20) & 1;
152 i->rn = (i->w >> 16) & 0xf;
153 i->rd = (i->w >> 12) & 0xf;
154 i->rs = (i->w >> 0) & 0xf;
155 if(i->rn == 15 && i->rs == 0) {
156 if(i->op == 8) {
157 format("MOVW", i,"CPSR, R%d");
158 return;
159 } else
160 if(i->op == 10) {
161 format("MOVW", i,"SPSR, R%d");
162 return;
163 }
164 } else
165 if(i->rn == 9 && i->rd == 15) {
166 if(i->op == 9) {
167 format("MOVW", i, "R%s, CPSR");
168 return;
169 } else
170 if(i->op == 11) {
171 format("MOVW", i, "R%s, SPSR");
172 return;
173 }
174 }
175 format(o->o, i, o->a);
176 }
177
178 static void
armdpi(Opcode * o,Instr * i)179 armdpi(Opcode *o, Instr *i)
180 {
181 ulong v;
182 int c;
183
184 v = (i->w >> 0) & 0xff;
185 c = (i->w >> 8) & 0xf;
186 while(c) {
187 v = (v<<30) | (v>>2);
188 c--;
189 }
190 i->imm = v;
191 i->store = (i->w >> 20) & 1;
192 i->rn = (i->w >> 16) & 0xf;
193 i->rd = (i->w >> 12) & 0xf;
194 i->rs = i->w&0x0f;
195
196 /* RET is encoded as ADD #0,R14,R15 */
197 if(i->w == 0xe282f000){
198 format("RET", i, "");
199 return;
200 } else
201 format(o->o, i, o->a);
202 }
203
204 static void
armsdti(Opcode * o,Instr * i)205 armsdti(Opcode *o, Instr *i)
206 {
207 ulong v;
208
209 v = (i->w >> 0) & 0xfff;
210 if(!(i->w & (1<<23)))
211 v = -v;
212 i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
213 i->imm = v;
214 i->rn = (i->w >> 16) & 0xf;
215 i->rd = (i->w >> 12) & 0xf;
216 /* convert load of offset(PC) to a load immediate */
217 if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0)
218 format(o->o, i, "$#%i,R%d");
219 else
220 format(o->o, i, o->a);
221 }
222
223 static void
armsdts(Opcode * o,Instr * i)224 armsdts(Opcode *o, Instr *i)
225 {
226 i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
227 i->rs = (i->w >> 0) & 0xf;
228 i->rn = (i->w >> 16) & 0xf;
229 i->rd = (i->w >> 12) & 0xf;
230 format(o->o, i, o->a);
231 }
232
233 static void
armbdt(Opcode * o,Instr * i)234 armbdt(Opcode *o, Instr *i)
235 {
236 i->store = (i->w >> 21) & 0x3; /* S & W bits */
237 i->rn = (i->w >> 16) & 0xf;
238 i->imm = i->w & 0xffff;
239 if(i->w == 0xe8fd8000)
240 format("RFE", i, "");
241 else
242 format(o->o, i, o->a);
243 }
244
245 static void
armund(Opcode * o,Instr * i)246 armund(Opcode *o, Instr *i)
247 {
248 format(o->o, i, o->a);
249 }
250
251 static void
armcdt(Opcode * o,Instr * i)252 armcdt(Opcode *o, Instr *i)
253 {
254 format(o->o, i, o->a);
255 }
256
257 static void
armunk(Opcode * o,Instr * i)258 armunk(Opcode *o, Instr *i)
259 {
260 format(o->o, i, o->a);
261 }
262
263 static void
armb(Opcode * o,Instr * i)264 armb(Opcode *o, Instr *i)
265 {
266 ulong v;
267
268 v = i->w & 0xffffff;
269 if(v & 0x800000)
270 v |= ~0xffffff;
271 i->imm = (v<<2) + i->addr + 8;
272 format(o->o, i, o->a);
273 }
274
275 static void
armco(Opcode * o,Instr * i)276 armco(Opcode *o, Instr *i) /* coprocessor instructions */
277 {
278 int op, p, cp;
279
280 char buf[1024];
281
282 i->rn = (i->w >> 16) & 0xf;
283 i->rd = (i->w >> 12) & 0xf;
284 i->rs = i->w&0xf;
285 cp = (i->w >> 8) & 0xf;
286 p = (i->w >> 5) & 0x7;
287 if(i->w&0x10) {
288 op = (i->w >> 20) & 0x0f;
289 snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
290 } else {
291 op = (i->w >> 21) & 0x07;
292 snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
293 }
294 format(o->o, i, buf);
295 }
296
297 static Opcode opcodes[] =
298 {
299 "AND%C%S", armdps, "R%s,R%n,R%d",
300 "EOR%C%S", armdps, "R%s,R%n,R%d",
301 "SUB%C%S", armdps, "R%s,R%n,R%d",
302 "RSB%C%S", armdps, "R%s,R%n,R%d",
303 "ADD%C%S", armdps, "R%s,R%n,R%d",
304 "ADC%C%S", armdps, "R%s,R%n,R%d",
305 "SBC%C%S", armdps, "R%s,R%n,R%d",
306 "RSC%C%S", armdps, "R%s,R%n,R%d",
307 "TST%C%S", armdps, "R%s,R%n,",
308 "TEQ%C%S", armdps, "R%s,R%n,",
309 "CMP%C%S", armdps, "R%s,R%n,",
310 "CMN%C%S", armdps, "R%s,R%n,",
311 "ORR%C%S", armdps, "R%s,R%n,R%d",
312 "MOVW%C%S", armdps, "R%s,R%d",
313 "BIC%C%S", armdps, "R%s,R%n,R%d",
314 "MVN%C%S", armdps, "R%s,R%d",
315
316 "AND%C%S", armdps, "(R%s%h#%m),R%n,R%d",
317 "EOR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
318 "SUB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
319 "RSB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
320 "ADD%C%S", armdps, "(R%s%h#%m),R%n,R%d",
321 "ADC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
322 "SBC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
323 "RSC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
324 "TST%C%S", armdps, "(R%s%h#%m),R%n,",
325 "TEQ%C%S", armdps, "(R%s%h#%m),R%n,",
326 "CMP%C%S", armdps, "(R%s%h#%m),R%n,",
327 "CMN%C%S", armdps, "(R%s%h#%m),R%n,",
328 "ORR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
329 "MOVW%C%S", armdps, "(R%s%h#%m),R%d",
330 "BIC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
331 "MVN%C%S", armdps, "(R%s%h#%m),R%d",
332
333 "AND%C%S", armdps, "(R%s%hR%m),R%n,R%d",
334 "EOR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
335 "SUB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
336 "RSB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
337 "ADD%C%S", armdps, "(R%s%hR%m),R%n,R%d",
338 "ADC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
339 "SBC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
340 "RSC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
341 "TST%C%S", armdps, "(R%s%hR%m),R%n,",
342 "TEQ%C%S", armdps, "(R%s%hR%m),R%n,",
343 "CMP%C%S", armdps, "(R%s%hR%m),R%n,",
344 "CMN%C%S", armdps, "(R%s%hR%m),R%n,",
345 "ORR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
346 "MOVW%C%S", armdps, "(R%s%hR%m),R%d",
347 "BIC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
348 "MVN%C%S", armdps, "(R%s%hR%m),R%d",
349
350 "AND%C%S", armdpi, "$#%i,R%n,R%d",
351 "EOR%C%S", armdpi, "$#%i,R%n,R%d",
352 "SUB%C%S", armdpi, "$#%i,R%n,R%d",
353 "RSB%C%S", armdpi, "$#%i,R%n,R%d",
354 "ADD%C%S", armdpi, "$#%i,R%n,R%d",
355 "ADC%C%S", armdpi, "$#%i,R%n,R%d",
356 "SBC%C%S", armdpi, "$#%i,R%n,R%d",
357 "RSC%C%S", armdpi, "$#%i,R%n,R%d",
358 "TST%C%S", armdpi, "$#%i,R%n,",
359 "TEQ%C%S", armdpi, "$#%i,R%n,",
360 "CMP%C%S", armdpi, "$#%i,R%n,",
361 "CMN%C%S", armdpi, "$#%i,R%n,",
362 "ORR%C%S", armdpi, "$#%i,R%n,R%d",
363 "MOVW%C%S", armdpi, "$#%i,,R%d",
364 "BIC%C%S", armdpi, "$#%i,R%n,R%d",
365 "MVN%C%S", armdpi, "$#%i,,R%d",
366
367 "MUL%C%S", armdpi, "R%s,R%m,R%n",
368 "MULA%C%S", armdpi, "R%s,R%m,R%n,R%d",
369 "SWPW", armdpi, "R%s,(R%n),R%d",
370 "SWPB", armdpi, "R%s,(R%n),R%d",
371
372 "MOVW%C%p", armsdti,"R%d,#%i(R%n)",
373 "MOVB%C%p", armsdti,"R%d,#%i(R%n)",
374 "MOVW%C%p", armsdti,"#%i(R%n),R%d",
375 "MOVB%C%p", armsdti,"#%i(R%n),R%d",
376
377 "MOVW%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
378 "MOVB%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
379 "MOVW%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
380 "MOVB%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
381
382 "MOVM%C%P%a", armbdt, "R%n,[%r]",
383 "MOVM%C%P%a", armbdt, "[%r],R%n",
384
385 "B%C", armb, "%b",
386 "BL%C", armb, "%b",
387
388 "CDP%C", armco, "",
389 "CDP%C", armco, "",
390 "MCR%C", armco, "",
391 "MRC%C", armco, "",
392
393 "UNK", armunk, "",
394 };
395
396 static char *mode[] = { 0, "IA", "DB", "IB" };
397 static char *pw[] = { "P", "PW", 0, "W" };
398 static char *sw[] = { 0, "W", "S", "SW" };
399
400 static void
format(char * mnemonic,Instr * i,char * f)401 format(char *mnemonic, Instr *i, char *f)
402 {
403 int j, k, m, n;
404
405 if(mnemonic)
406 format(0, i, mnemonic);
407 if(f == 0)
408 return;
409 if(mnemonic)
410 if(i->curr < i->end)
411 *i->curr++ = '\t';
412 for ( ; *f && i->curr < i->end; f++) {
413 if(*f != '%') {
414 *i->curr++ = *f;
415 continue;
416 }
417 switch (*++f) {
418
419 case 'C': /* .CONDITION */
420 if(cond[i->cond])
421 bprint(i, ".%s", cond[i->cond]);
422 break;
423
424 case 'S': /* .STORE */
425 if(i->store)
426 bprint(i, ".S");
427 break;
428
429 case 'P': /* P & U bits for block move */
430 n = (i->w >>23) & 0x3;
431 if (mode[n])
432 bprint(i, ".%s", mode[n]);
433 break;
434
435 case 'D': /* ~U bit for single data xfer */
436 if((i->w & (1<<23)) == 0)
437 bprint(i, "-");
438 break;
439
440 case 'p': /* P & W bits for single data xfer*/
441 if (pw[i->store])
442 bprint(i, ".%s", pw[i->store]);
443 break;
444
445 case 'a': /* S & W bits for single data xfer*/
446 if (sw[i->store])
447 bprint(i, ".%s", sw[i->store]);
448 break;
449
450 case 's':
451 bprint(i, "%d", i->rs & 0xf);
452 break;
453
454 case 'm':
455 bprint(i, "%d", (i->w>>7) & 0x1f);
456 break;
457
458 case 'h':
459 bprint(i, "%s", shtype[(i->w>>5) & 0x3]);
460 break;
461
462 case 'n':
463 bprint(i, "%d", i->rn);
464 break;
465
466 case 'd':
467 bprint(i, "%d", i->rd);
468 break;
469
470 case 'i':
471 bprint(i, "%lux", i->imm);
472 break;
473
474 case 'b':
475 bprint(i, "%lux", i->imm);
476 break;
477
478 case 'r':
479 n = i->imm&0xffff;
480 j = 0;
481 k = 0;
482 while(n) {
483 m = j;
484 while(n&0x1) {
485 j++;
486 n >>= 1;
487 }
488 if(j != m) {
489 if(k)
490 bprint(i, ",");
491 if(j == m+1)
492 bprint(i, "R%d", m);
493 else
494 bprint(i, "R%d-R%d", m, j-1);
495 k = 1;
496 }
497 j++;
498 n >>= 1;
499 }
500 break;
501
502 case '\0':
503 *i->curr++ = '%';
504 return;
505
506 default:
507 bprint(i, "%%%c", *f);
508 break;
509 }
510 }
511 *i->curr = 0;
512 }
513
514 void
das(ulong * x,int n)515 das(ulong *x, int n)
516 {
517 ulong pc;
518 Instr i;
519 char buf[128];
520
521 pc = (ulong)x;
522 while(n > 0) {
523 i.curr = buf;
524 i.end = buf+sizeof(buf)-1;
525
526 if(decode(pc, &i) < 0)
527 sprint(buf, "???");
528 else
529 (*opcodes[i.op].f)(&opcodes[i.op], &i);
530
531 print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
532 pc += 4;
533 n--;
534 }
535 }
536