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 51 get4(ulong addr, long *v) 52 { 53 *v = *(ulong*)addr; 54 return 1; 55 } 56 57 static char * 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 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 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 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 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 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 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 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 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 246 armund(Opcode *o, Instr *i) 247 { 248 format(o->o, i, o->a); 249 } 250 251 static void 252 armcdt(Opcode *o, Instr *i) 253 { 254 format(o->o, i, o->a); 255 } 256 257 static void 258 armunk(Opcode *o, Instr *i) 259 { 260 format(o->o, i, o->a); 261 } 262 263 static void 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 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 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 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