FreeCalypso > hg > freecalypso-reveng
comparison leo-obj/tool/armdis.c @ 130:87b82398a08b
leo-obj project subtree started, tiobjd tool moved into it
| author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
|---|---|
| date | Sun, 06 Apr 2014 22:14:39 +0000 |
| parents | ticoff/armdis.c@2f23301d2f86 |
| children | 2767ff8d26d5 |
comparison
equal
deleted
inserted
replaced
| 129:597143ba1c37 | 130:87b82398a08b |
|---|---|
| 1 /* | |
| 2 * ARM state disassembly | |
| 3 */ | |
| 4 | |
| 5 #include <sys/types.h> | |
| 6 #include <stdio.h> | |
| 7 #include <stdlib.h> | |
| 8 #include <string.h> | |
| 9 #include <strings.h> | |
| 10 #include "intstruct.h" | |
| 11 #include "globals.h" | |
| 12 | |
| 13 extern unsigned get_u16(), get_u32(); | |
| 14 extern struct internal_reloc *find_word32_reloc(); | |
| 15 | |
| 16 extern char *regnames[16], *condition_decode[16], *shift_types[4]; | |
| 17 | |
| 18 static char *dataproc_ops[16] = {"and", "eor", "sub", "rsb", | |
| 19 "add", "adc", "sbc", "rsc", | |
| 20 "tst", "teq", "cmp", "cmn", | |
| 21 "orr", "mov", "bic", "mvn"}; | |
| 22 | |
| 23 static void | |
| 24 arm_branch(off, word) | |
| 25 unsigned off, word; | |
| 26 { | |
| 27 unsigned dest; | |
| 28 | |
| 29 dest = (word & 0x00FFFFFF) << 2; | |
| 30 if (dest & 0x02000000) | |
| 31 dest |= 0xFC000000; | |
| 32 dest += off + 8; | |
| 33 printf("b%s%s\t0x%x\n", word&0x1000000 ? "l" : "", | |
| 34 condition_decode[word>>28], dest); | |
| 35 } | |
| 36 | |
| 37 static void | |
| 38 op2_immed(word) | |
| 39 unsigned word; | |
| 40 { | |
| 41 unsigned low8, rot, val; | |
| 42 | |
| 43 low8 = word & 0xFF; | |
| 44 rot = (word & 0xF00) >> 7; | |
| 45 val = (low8 << (32 - rot)) | (low8 >> rot); | |
| 46 if (val <= 9) | |
| 47 printf("#%u\n", val); | |
| 48 else | |
| 49 printf("#%u\t; 0x%x\n", val, val); | |
| 50 } | |
| 51 | |
| 52 static void | |
| 53 op2_regbyconst(word) | |
| 54 unsigned word; | |
| 55 { | |
| 56 unsigned c, t; | |
| 57 | |
| 58 c = (word >> 7) & 0x1F; | |
| 59 t = (word >> 5) & 3; | |
| 60 if (!c) { | |
| 61 switch (t) { | |
| 62 case 0: | |
| 63 printf("%s", regnames[word&0xF]); | |
| 64 return; | |
| 65 case 3: | |
| 66 printf("%s, rrx", regnames[word&0xF]); | |
| 67 return; | |
| 68 default: | |
| 69 c = 32; | |
| 70 } | |
| 71 } | |
| 72 printf("%s, %s #%u", regnames[word&0xF], shift_types[t], c); | |
| 73 } | |
| 74 | |
| 75 static void | |
| 76 op2_regbyreg(word) | |
| 77 unsigned word; | |
| 78 { | |
| 79 printf("%s, %s %s", regnames[word&0xF], shift_types[(word>>5)&3], | |
| 80 regnames[(word>>8)&0xF]); | |
| 81 } | |
| 82 | |
| 83 static void | |
| 84 op2_regshift(word) | |
| 85 unsigned word; | |
| 86 { | |
| 87 if (word & 0x10) | |
| 88 op2_regbyreg(word); | |
| 89 else | |
| 90 op2_regbyconst(word); | |
| 91 putchar('\n'); | |
| 92 } | |
| 93 | |
| 94 static void | |
| 95 dataproc_op2(word) | |
| 96 unsigned word; | |
| 97 { | |
| 98 if (word & 0x02000000) | |
| 99 op2_immed(word); | |
| 100 else | |
| 101 op2_regshift(word); | |
| 102 } | |
| 103 | |
| 104 static void | |
| 105 dataproc_tstcmp_overlay(word) | |
| 106 unsigned word; | |
| 107 { | |
| 108 char msrmask[5], *cp; | |
| 109 | |
| 110 if ((word & 0x0FFFFFF0) == 0x012FFF10) { | |
| 111 printf("bx%s\t%s\n", condition_decode[word>>28], | |
| 112 regnames[word&0xF]); | |
| 113 return; | |
| 114 } else if ((word & 0x0FBF0FFF) == 0x010F0000) { | |
| 115 printf("mrs%s\t%s, %cPSR\n", condition_decode[word>>28], | |
| 116 regnames[(word>>12)&0xF], word&0x400000 ? 'S' : 'C'); | |
| 117 return; | |
| 118 } else if ((word & 0x0DB0F000) == 0x0120F000) { | |
| 119 if (!(word & 0x02000000) && (word & 0xFF0)) { | |
| 120 printf("<invalid MSR>\n"); | |
| 121 return; | |
| 122 } | |
| 123 if (word & 0xF0000) { | |
| 124 cp = msrmask; | |
| 125 if (word & 0x80000) | |
| 126 *cp++ = 'f'; | |
| 127 if (word & 0x40000) | |
| 128 *cp++ = 's'; | |
| 129 if (word & 0x20000) | |
| 130 *cp++ = 'x'; | |
| 131 if (word & 0x10000) | |
| 132 *cp++ = 'c'; | |
| 133 *cp = '\0'; | |
| 134 } else | |
| 135 strcpy(msrmask, "null"); | |
| 136 printf("msr%s\t%cPSR_%s, ", condition_decode[word>>28], | |
| 137 word&0x400000 ? 'S' : 'C', msrmask); | |
| 138 dataproc_op2(word); | |
| 139 return; | |
| 140 } | |
| 141 printf("<invalid BX/MRS/MSR>\n"); | |
| 142 } | |
| 143 | |
| 144 static void | |
| 145 dataproc(word) | |
| 146 unsigned word; | |
| 147 { | |
| 148 unsigned opc; | |
| 149 | |
| 150 opc = (word >> 21) & 0xF; | |
| 151 switch (opc) { | |
| 152 case 0: | |
| 153 case 1: | |
| 154 case 2: | |
| 155 case 3: | |
| 156 case 4: | |
| 157 case 5: | |
| 158 case 6: | |
| 159 case 7: | |
| 160 case 0xC: | |
| 161 case 0xE: | |
| 162 printf("%s%s%s\t%s, %s, ", dataproc_ops[opc], | |
| 163 condition_decode[word>>28], word&0x100000 ? "s" : "", | |
| 164 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
| 165 dataproc_op2(word); | |
| 166 return; | |
| 167 case 0xD: | |
| 168 case 0xF: | |
| 169 printf("%s%s%s\t%s, ", dataproc_ops[opc], | |
| 170 condition_decode[word>>28], word&0x100000 ? "s" : "", | |
| 171 regnames[(word>>12)&0xF]); | |
| 172 dataproc_op2(word); | |
| 173 return; | |
| 174 case 8: | |
| 175 case 9: | |
| 176 case 0xA: | |
| 177 case 0xB: | |
| 178 if (word & 0x100000) { | |
| 179 printf("%s%s\t%s, ", dataproc_ops[opc], | |
| 180 condition_decode[word>>28], | |
| 181 regnames[(word>>16)&0xF]); | |
| 182 dataproc_op2(word); | |
| 183 } else | |
| 184 dataproc_tstcmp_overlay(word); | |
| 185 return; | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 static void | |
| 190 multiply(word) | |
| 191 unsigned word; | |
| 192 { | |
| 193 if ((word & 0x0FE000F0) == 0x90) | |
| 194 printf("mul%s%s\t%s, %s, %s\n", condition_decode[word>>28], | |
| 195 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], | |
| 196 regnames[word&0xF], regnames[(word>>8)&0xF]); | |
| 197 else if ((word & 0x0FE000F0) == 0x00200090) | |
| 198 printf("mla%s%s\t%s, %s, %s, %s\n", condition_decode[word>>28], | |
| 199 word&0x100000 ? "s" : "", regnames[(word>>16)&0xF], | |
| 200 regnames[word&0xF], regnames[(word>>8)&0xF], | |
| 201 regnames[(word>>12)&0xF]); | |
| 202 else if ((word & 0x0F8000F0) == 0x00800090) | |
| 203 printf("%c%sl%s%s\t%s, %s, %s, %s\n", | |
| 204 word&0x400000 ? 's' : 'u', | |
| 205 word&0x200000 ? "mla" : "mul", | |
| 206 condition_decode[word>>28], | |
| 207 word&0x100000 ? "s" : "", | |
| 208 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], | |
| 209 regnames[word&0xF], regnames[(word>>8)&0xF]); | |
| 210 else if ((word & 0x0FB00FF0) == 0x01000090) | |
| 211 printf("swp%s%s\t%s, %s, [%s]\n", condition_decode[word>>28], | |
| 212 word&0x400000, "b", "", regnames[(word>>12)&0xF], | |
| 213 regnames[word&0xF], regnames[(word>>16)&0xF]); | |
| 214 else | |
| 215 printf("<invalid multiply>\n"); | |
| 216 } | |
| 217 | |
| 218 static int | |
| 219 check_ldr_litpool(sec, off, word, loff, size) | |
| 220 struct internal_scnhdr *sec; | |
| 221 unsigned off, word, loff; | |
| 222 { | |
| 223 unsigned litoff, datum; | |
| 224 struct internal_reloc *rel; | |
| 225 | |
| 226 /* base reg must be 15 */ | |
| 227 if (((word >> 16) & 0xF) != 15) | |
| 228 return(0); | |
| 229 /* must be a load */ | |
| 230 if (!(word & 0x100000)) | |
| 231 return(0); | |
| 232 /* no writeback allowed */ | |
| 233 if (word & 0x200000) | |
| 234 return(0); | |
| 235 /* alignment */ | |
| 236 if (loff & (size - 1)) | |
| 237 return(0); | |
| 238 /* range */ | |
| 239 off += 8; | |
| 240 if (word & 0x800000) | |
| 241 litoff = off + loff; | |
| 242 else { | |
| 243 if (loff > off) | |
| 244 return(0); | |
| 245 litoff = off - loff; | |
| 246 } | |
| 247 if (litoff >= sec->size) | |
| 248 return(0); | |
| 249 /* all checks passed, proceed */ | |
| 250 rel = find_word32_reloc(sec, litoff); | |
| 251 switch (size) { | |
| 252 case 1: | |
| 253 datum = filemap[sec->data_offset + litoff]; | |
| 254 break; | |
| 255 case 2: | |
| 256 datum = get_u16(filemap + sec->data_offset + litoff); | |
| 257 break; | |
| 258 case 4: | |
| 259 datum = get_u32(filemap + sec->data_offset + litoff); | |
| 260 break; | |
| 261 } | |
| 262 putchar('='); | |
| 263 if (rel) | |
| 264 disasm_reloc_target(sec, rel, datum); | |
| 265 else | |
| 266 printf("0x%x", datum); | |
| 267 printf("\t; via 0x%x\n", litoff); | |
| 268 return(1); | |
| 269 } | |
| 270 | |
| 271 static void | |
| 272 ldr_str_imm_pre(sec, off, word) | |
| 273 struct internal_scnhdr *sec; | |
| 274 unsigned off, word; | |
| 275 { | |
| 276 unsigned loff = word & 0xFFF; | |
| 277 | |
| 278 printf("%s%s%s\t%s, ", word&0x100000 ? "ldr" : "str", | |
| 279 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
| 280 regnames[(word>>12)&0xF]); | |
| 281 if (check_ldr_litpool(sec, off, word, loff, word&0x400000 ? 1 : 4)) | |
| 282 return; | |
| 283 printf("[%s", regnames[(word>>16)&0xF]); | |
| 284 if (loff || word&0x200000) | |
| 285 printf(", #%s%u", word&0x800000 ? "" : "-", loff); | |
| 286 putchar(']'); | |
| 287 if (word & 0x200000) | |
| 288 putchar('!'); | |
| 289 if (loff >= 10) | |
| 290 printf("\t; 0x%x", loff); | |
| 291 putchar('\n'); | |
| 292 } | |
| 293 | |
| 294 static void | |
| 295 ldr_str_imm_post(word) | |
| 296 unsigned word; | |
| 297 { | |
| 298 unsigned loff = word & 0xFFF; | |
| 299 | |
| 300 printf("%s%s%s%s\t%s, [%s], #%s%u", word&0x100000 ? "ldr" : "str", | |
| 301 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
| 302 word&0x200000 ? "t" : "", | |
| 303 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF], | |
| 304 word&0x800000 ? "" : "-", loff); | |
| 305 if (loff >= 10) | |
| 306 printf("\t; 0x%x", loff); | |
| 307 putchar('\n'); | |
| 308 } | |
| 309 | |
| 310 static void | |
| 311 ldr_str_reg_pre(word) | |
| 312 unsigned word; | |
| 313 { | |
| 314 if (word & 0x10) { | |
| 315 printf("<invalid ldr/str: offset reg shift by reg>\n"); | |
| 316 return; | |
| 317 } | |
| 318 printf("%s%s%s\t%s, [%s, ", word&0x100000 ? "ldr" : "str", | |
| 319 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
| 320 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
| 321 if (!(word & 0x800000)) | |
| 322 putchar('-'); | |
| 323 op2_regbyconst(word); | |
| 324 putchar(']'); | |
| 325 if (word & 0x200000) | |
| 326 putchar('!'); | |
| 327 putchar('\n'); | |
| 328 } | |
| 329 | |
| 330 static void | |
| 331 ldr_str_reg_post(word) | |
| 332 unsigned word; | |
| 333 { | |
| 334 if (word & 0x10) { | |
| 335 printf("<invalid ldr/str: offset reg shift by reg>\n"); | |
| 336 return; | |
| 337 } | |
| 338 printf("%s%s%s%s\t%s, [%s], ", word&0x100000 ? "ldr" : "str", | |
| 339 condition_decode[word>>28], word&0x400000 ? "b" : "", | |
| 340 word&0x200000 ? "t" : "", | |
| 341 regnames[(word>>12)&0xF], regnames[(word>>16)&0xF]); | |
| 342 if (!(word & 0x800000)) | |
| 343 putchar('-'); | |
| 344 op2_regbyconst(word); | |
| 345 putchar('\n'); | |
| 346 } | |
| 347 | |
| 348 static void | |
| 349 ldr_str_ext(sec, off, word) | |
| 350 struct internal_scnhdr *sec; | |
| 351 unsigned off, word; | |
| 352 { | |
| 353 unsigned loff; | |
| 354 | |
| 355 if (!(word&0x01000000) && word&0x200000) { | |
| 356 printf("<invalid ldrh/strh: P=0, W=1>\n"); | |
| 357 return; | |
| 358 } | |
| 359 if (!(word&0x400000) && word&0xF00) { | |
| 360 printf("<invalid ldrh/strh: SBZ!=0>\n"); | |
| 361 return; | |
| 362 } | |
| 363 printf("%s%s%s%c\t%s, ", word&0x100000 ? "ldr" : "str", | |
| 364 condition_decode[word>>28], | |
| 365 word&0x40 ? "s" : "", | |
| 366 word&0x20 ? 'h' : 'b', | |
| 367 regnames[(word>>12)&0xF]); | |
| 368 if (word & 0x400000) | |
| 369 loff = ((word & 0xF00) >> 4) | (word & 0xF); | |
| 370 switch (word & 0x01400000) { | |
| 371 case 0: | |
| 372 /* reg post */ | |
| 373 printf("[%s], %s%s", regnames[(word>>16)&0xF], | |
| 374 word&0x800000 ? "" : "-", regnames[word&0xF]); | |
| 375 break; | |
| 376 case 0x400000: | |
| 377 /* imm post */ | |
| 378 printf("[%s], #%s%u", regnames[(word>>16)&0xF], | |
| 379 word&0x800000 ? "" : "-", loff); | |
| 380 if (loff >= 10) | |
| 381 printf("\t; 0x%x", loff); | |
| 382 break; | |
| 383 case 0x01000000: | |
| 384 /* reg pre */ | |
| 385 printf("[%s, %s%s]%s", regnames[(word>>16)&0xF], | |
| 386 word&0x800000 ? "" : "-", regnames[word&0xF], | |
| 387 word&0x200000 ? "!" : ""); | |
| 388 break; | |
| 389 case 0x01400000: | |
| 390 /* imm pre */ | |
| 391 if (check_ldr_litpool(sec, off, word, loff, word&0x20 ? 2 : 1)) | |
| 392 return; | |
| 393 printf("[%s", regnames[(word>>16)&0xF]); | |
| 394 if (loff || word&0x200000) | |
| 395 printf(", #%s%u", word&0x800000 ? "" : "-", loff); | |
| 396 putchar(']'); | |
| 397 if (word & 0x200000) | |
| 398 putchar('!'); | |
| 399 if (loff >= 10) | |
| 400 printf("\t; 0x%x", loff); | |
| 401 break; | |
| 402 } | |
| 403 putchar('\n'); | |
| 404 } | |
| 405 | |
| 406 static void | |
| 407 dataproc_74_overlay(sec, off, word) | |
| 408 struct internal_scnhdr *sec; | |
| 409 unsigned off, word; | |
| 410 { | |
| 411 if (word & 0x60) | |
| 412 ldr_str_ext(sec, off, word); | |
| 413 else | |
| 414 multiply(word); | |
| 415 } | |
| 416 | |
| 417 static void | |
| 418 ldm_stm(word) | |
| 419 unsigned word; | |
| 420 { | |
| 421 int r, flag; | |
| 422 | |
| 423 printf("%s%s%c%c\t%s", word&0x100000 ? "ldm" : "stm", | |
| 424 condition_decode[word>>28], | |
| 425 word&0x800000 ? 'i' : 'd', word&0x01000000 ? 'b' : 'a', | |
| 426 regnames[(word>>16)&0xF]); | |
| 427 if (word & 0x200000) | |
| 428 putchar('!'); | |
| 429 fputs(", {", stdout); | |
| 430 flag = 0; | |
| 431 for (r = 0; r < 16; r++) | |
| 432 if (word & (1 << r)) { | |
| 433 if (flag) | |
| 434 fputs(", ", stdout); | |
| 435 fputs(regnames[r], stdout); | |
| 436 flag = 1; | |
| 437 } | |
| 438 putchar('}'); | |
| 439 if (word & 0x400000) | |
| 440 putchar('^'); | |
| 441 putchar('\n'); | |
| 442 } | |
| 443 | |
| 444 void | |
| 445 arm_disasm_line(sec, off) | |
| 446 struct internal_scnhdr *sec; | |
| 447 unsigned off; | |
| 448 { | |
| 449 unsigned word; | |
| 450 | |
| 451 word = get_u32(filemap + sec->data_offset + off); | |
| 452 printf("%08x\t", word); | |
| 453 if ((word >> 28) == 0xF) { | |
| 454 printf("<invalid-F>\n"); | |
| 455 return; | |
| 456 } | |
| 457 switch ((word >> 24) & 0xF) { | |
| 458 case 0: | |
| 459 case 1: | |
| 460 if ((word & 0x90) == 0x90) | |
| 461 dataproc_74_overlay(sec, off, word); | |
| 462 else | |
| 463 dataproc(word); | |
| 464 return; | |
| 465 case 2: | |
| 466 case 3: | |
| 467 dataproc(word); | |
| 468 return; | |
| 469 case 4: | |
| 470 ldr_str_imm_post(word); | |
| 471 return; | |
| 472 case 5: | |
| 473 ldr_str_imm_pre(sec, off, word); | |
| 474 return; | |
| 475 case 6: | |
| 476 ldr_str_reg_post(word); | |
| 477 return; | |
| 478 case 7: | |
| 479 ldr_str_reg_pre(word); | |
| 480 return; | |
| 481 case 8: | |
| 482 case 9: | |
| 483 ldm_stm(word); | |
| 484 return; | |
| 485 case 0xA: | |
| 486 case 0xB: | |
| 487 arm_branch(off, word); | |
| 488 return; | |
| 489 case 0xC: | |
| 490 case 0xD: | |
| 491 case 0xE: | |
| 492 printf("<COPROCESSOR>\n"); | |
| 493 return; | |
| 494 case 0xF: | |
| 495 printf("swi%s\t0x%x\n", condition_decode[word>>28], | |
| 496 word & 0xFFFFFF); | |
| 497 return; | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 void | |
| 502 arm_branch_reloc(sec, rel) | |
| 503 struct internal_scnhdr *sec; | |
| 504 struct internal_reloc *rel; | |
| 505 { | |
| 506 unsigned word, dest; | |
| 507 | |
| 508 word = get_u32(filemap + sec->data_offset + rel->location); | |
| 509 printf("%08x R\t", word); | |
| 510 if ((word & 0x0E000000) != 0x0A000000) { | |
| 511 printf("<invalid ARM_B reloc: opcode not B or BL>\n"); | |
| 512 return; | |
| 513 } | |
| 514 dest = (word & 0x00FFFFFF) << 2; | |
| 515 if (dest & 0x02000000) | |
| 516 dest |= 0xFC000000; | |
| 517 dest += rel->location + 8; | |
| 518 printf("b%s%s\t", word&0x1000000 ? "l" : "", | |
| 519 condition_decode[word>>28]); | |
| 520 disasm_reloc_target(sec, rel, dest); | |
| 521 putchar('\n'); | |
| 522 } |
