1 #include <lib9.h> 2 #include <bio.h> 3 #include "mach.h" 4 5 static int debug = 0; 6 7 typedef struct Instr Instr; 8 struct Instr 9 { 10 Map *map; 11 ulong w; 12 ulong addr; 13 uchar op; /* super opcode */ 14 15 uchar rd; 16 uchar rn; 17 uchar rs; 18 19 long imm; /* imm */ 20 21 char* curr; /* fill point in buffer */ 22 char* end; /* end of buffer */ 23 char* err; /* error message */ 24 }; 25 26 typedef struct Opcode Opcode; 27 struct Opcode 28 { 29 char* o; 30 void (*fmt)(Opcode*, Instr*); 31 ulong (*foll)(Map*, Rgetter, Instr*, ulong); 32 char* a; 33 }; 34 35 static void format(char*, Instr*, char*); 36 static char FRAMENAME[] = ".frame"; 37 38 /* 39 * Thumb-specific debugger interface 40 */ 41 42 static char *thumbexcep(Map*, Rgetter); 43 static int thumbfoll(Map*, ulong, Rgetter, ulong*); 44 static int thumbinst(Map*, ulong, char, char*, int); 45 static int thumbdas(Map*, ulong, char*, int); 46 static int thumbinstlen(Map*, ulong); 47 48 /* 49 * Debugger interface 50 */ 51 Machdata thumbmach = 52 { 53 {0x0, 0xE8}, /* break point */ 54 2, /* break point size */ 55 56 leswab, /* short to local byte order */ 57 leswal, /* long to local byte order */ 58 leswav, /* long to local byte order */ 59 risctrace, /* C traceback */ 60 riscframe, /* Frame finder */ 61 thumbexcep, /* print exception */ 62 0, /* breakpoint fixup */ 63 0, /* single precision float printer */ 64 0, /* double precision float printer */ 65 thumbfoll, /* following addresses */ 66 thumbinst, /* print instruction */ 67 thumbdas, /* dissembler */ 68 thumbinstlen, /* instruction size */ 69 }; 70 71 static void thumbrrh(Opcode *, Instr *); 72 static void thumbbcc(Opcode *, Instr *); 73 static void thumbb(Opcode *, Instr *); 74 static void thumbbl(Opcode *, Instr *); 75 76 static char* 77 thumbexcep(Map *map, Rgetter rget) 78 { 79 long c; 80 81 c = (*rget)(map, "TYPE"); 82 switch (c&0x1f) { 83 case 0x11: 84 return "Fiq interrupt"; 85 case 0x12: 86 return "Mirq interrupt"; 87 case 0x13: 88 return "SVC/SWI Exception"; 89 case 0x17: 90 return "Prefetch Abort/Data Abort"; 91 case 0x18: 92 return "Data Abort"; 93 case 0x1b: 94 return "Undefined instruction/Breakpoint"; 95 case 0x1f: 96 return "Sys trap"; 97 default: 98 return "Undefined trap"; 99 } 100 } 101 102 static 103 char* cond[16] = 104 { 105 "EQ", "NE", "CS", "CC", 106 "MI", "PL", "VS", "VC", 107 "HI", "LS", "GE", "LT", 108 "GT", "LE", "\0", "NV" 109 }; 110 111 #define B(h, l) bits(ins, h, l) 112 113 static int 114 bits(int i, int h, int l) 115 { 116 if(h < l) 117 print("h < l in bits"); 118 return (i&(((1<<(h-l+1))-1)<<l))>>l; 119 } 120 121 int 122 thumbclass(long w) 123 { 124 int o; 125 int ins = w; 126 127 if(ins&0xffff0000) 128 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; 129 o = B(15, 13); 130 switch(o){ 131 case 0: 132 o = B(12, 11); 133 switch(o){ 134 case 0: 135 case 1: 136 case 2: 137 return B(12, 11); 138 case 3: 139 if(B(10, 10) == 0) 140 return 3+B(9, 9); 141 else 142 return 3+2+B(9, 9); 143 } 144 case 1: 145 return 3+2+2+B(12, 11); 146 case 2: 147 o = B(12, 10); 148 if(o == 0) 149 return 3+2+2+4+B(9, 6); 150 if(o == 1){ 151 o = B(9, 8); 152 if(o == 3) 153 return 3+2+2+4+16+B(9, 8); 154 return 3+2+2+4+16+B(9, 8); 155 } 156 if(o == 2 || o == 3) 157 return 3+2+2+4+16+4; 158 return 3+2+2+4+16+4+1+B(11, 9); 159 case 3: 160 return 3+2+2+4+16+4+1+8+B(12, 11); 161 case 4: 162 if(B(12, 12) == 0) 163 return 3+2+2+4+16+4+1+8+4+B(11, 11); 164 return 3+2+2+4+16+4+1+8+6+B(11, 11); 165 case 5: 166 if(B(12, 12) == 0) 167 return 3+2+2+4+16+4+1+8+6+2+B(11, 11); 168 if(B(11, 8) == 0) 169 return 3+2+2+4+16+4+1+8+6+2+2+B(7, 7); 170 return 3+2+2+4+16+4+1+8+6+2+2+2+B(11, 11); 171 case 6: 172 if(B(12, 12) == 0) 173 return 3+2+2+4+16+4+1+8+6+2+2+2+2+B(11, 11); 174 if(B(11, 8) == 0xf) 175 return 3+2+2+4+16+4+1+8+6+2+2+2+4; 176 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1; 177 case 7: 178 o = B(12, 11); 179 switch(o){ 180 case 0: 181 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1; 182 case 1: 183 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+2; 184 case 2: 185 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1; 186 case 3: 187 return 3+2+2+4+16+4+1+8+6+2+2+2+4+1+1+1+1; 188 } 189 } 190 return 0; 191 } 192 193 static int 194 decode(Map *map, ulong pc, Instr *i) 195 { 196 ushort w; 197 198 if(get2(map, pc, &w) < 0) { 199 werrstr("can't read instruction: %r"); 200 return -1; 201 } 202 i->w = w; 203 i->addr = pc; 204 i->op = thumbclass(w); 205 i->map = map; 206 return 1; 207 } 208 209 static void 210 bprint(Instr *i, char *fmt, ...) 211 { 212 va_list arg; 213 214 va_start(arg, fmt); 215 i->curr = vseprint(i->curr, i->end, fmt, arg); 216 va_end(arg); 217 } 218 219 static int 220 plocal(Instr *i) 221 { 222 char *reg; 223 Symbol s; 224 char *fn; 225 int class; 226 int offset; 227 228 if(!findsym(i->addr, CTEXT, &s)) { 229 if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr); 230 return 0; 231 } 232 fn = s.name; 233 if (!findlocal(&s, FRAMENAME, &s)) { 234 if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name); 235 return 0; 236 } 237 if(s.value > i->imm) { 238 class = CAUTO; 239 offset = s.value-i->imm; 240 reg = "(SP)"; 241 } else { 242 class = CPARAM; 243 offset = i->imm-s.value-4; 244 reg = "(FP)"; 245 } 246 if(!getauto(&s, offset, class, &s)) { 247 if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn, 248 class == CAUTO ? " auto" : "param", offset); 249 return 0; 250 } 251 bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg); 252 return 1; 253 } 254 255 /* 256 * Print value v as name[+offset] 257 */ 258 static int 259 gsymoff(char *buf, int n, long v, int space) 260 { 261 Symbol s; 262 int r; 263 long delta; 264 265 r = delta = 0; /* to shut compiler up */ 266 if (v) { 267 r = findsym(v, space, &s); 268 if (r) 269 delta = v-s.value; 270 if (delta < 0) 271 delta = -delta; 272 } 273 if (v == 0 || r == 0 || delta >= 4096) 274 return snprint(buf, n, "#%lux", v); 275 if (strcmp(s.name, ".string") == 0) 276 return snprint(buf, n, "#%lux", v); 277 if (!delta) 278 return snprint(buf, n, "%s", s.name); 279 if (s.type != 't' && s.type != 'T') 280 return snprint(buf, n, "%s+%lux", s.name, v-s.value); 281 else 282 return snprint(buf, n, "#%lux", v); 283 } 284 285 static int 286 thumbcondpass(Map *map, Rgetter rget, uchar cond) 287 { 288 ulong psr; 289 uchar n; 290 uchar z; 291 uchar c; 292 uchar v; 293 294 psr = rget(map, "PSR"); 295 n = (psr >> 31) & 1; 296 z = (psr >> 30) & 1; 297 c = (psr >> 29) & 1; 298 v = (psr >> 28) & 1; 299 300 switch(cond) { 301 case 0: return z; 302 case 1: return !z; 303 case 2: return c; 304 case 3: return !c; 305 case 4: return n; 306 case 5: return !n; 307 case 6: return v; 308 case 7: return !v; 309 case 8: return c && !z; 310 case 9: return !c || z; 311 case 10: return n == v; 312 case 11: return n != v; 313 case 12: return !z && (n == v); 314 case 13: return z && (n != v); 315 case 14: return 1; 316 case 15: return 0; 317 } 318 return 0; 319 } 320 321 static ulong 322 thumbfbranch(Map *map, Rgetter rget, Instr *i, ulong pc) 323 { 324 char buf[8]; 325 326 if(i->op == 30){ // BX 327 thumbrrh(nil, i); 328 sprint(buf, "R%ud", i->rn); 329 return rget(map, buf)&~1; // clear T bit 330 } 331 if(i->op == 57){ // Bcc 332 thumbbcc(nil, i); 333 if(thumbcondpass(map, rget, (i->w >> 8) & 0xf)) 334 return i->imm; 335 return pc+2; 336 } 337 if(i->op == 58){ // B 338 thumbb(nil, i); 339 return i->imm; 340 } 341 if(i->op == 60){ // BL 342 thumbbl(nil, i); 343 return i->imm; 344 } 345 print("bad thumbfbranch call"); 346 return 0; 347 } 348 349 static ulong 350 thumbfmov(Map *map, Rgetter rget, Instr *i, ulong pc) 351 { 352 char buf[8]; 353 ulong rd; 354 355 thumbrrh(nil, i); 356 rd = i->rd; 357 if(rd != 15) 358 return pc+2; 359 sprint(buf, "R%ud", i->rn); 360 return rget(map, buf); 361 } 362 363 static ulong 364 thumbfadd(Map *map, Rgetter rget, Instr *i, ulong pc) 365 { 366 char buf[8]; 367 ulong rd, v; 368 369 thumbrrh(nil, i); 370 rd = i->rd; 371 if(rd != 15) 372 return pc+2; 373 sprint(buf, "R%ud", i->rn); 374 v = rget(map, buf); 375 sprint(buf, "R15"); 376 return rget(map, buf) + v; 377 } 378 379 static void 380 thumbshift(Opcode *o, Instr *i) 381 { 382 int ins = i->w; 383 384 i->rd = B(2, 0); 385 i->rn = B(5, 3); 386 i->imm = B(10, 6); 387 format(o->o, i, o->a); 388 } 389 390 static void 391 thumbrrr(Opcode *o, Instr *i) 392 { 393 int ins = i->w; 394 395 i->rd = B(2, 0); 396 i->rn = B(5, 3); 397 i->rs = B(8, 6); 398 format(o->o, i, o->a); 399 } 400 401 static void 402 thumbirr(Opcode *o, Instr *i) 403 { 404 int ins = i->w; 405 406 i->rd = B(2, 0); 407 i->rn = B(5, 3); 408 i->imm = B(8, 6); 409 format(o->o, i, o->a); 410 } 411 412 static void 413 thumbir(Opcode *o, Instr *i) 414 { 415 int ins = i->w; 416 417 i->rd = B(10, 8); 418 i->imm = B(7, 0); 419 format(o->o, i, o->a); 420 } 421 422 static void 423 thumbrr(Opcode *o, Instr *i) 424 { 425 int ins = i->w; 426 427 i->rd = B(2, 0); 428 i->rn = B(5, 3); 429 format(o->o, i, o->a); 430 } 431 432 static void 433 thumbrrh(Opcode *o, Instr *i) 434 { 435 int ins = i->w; 436 437 i->rd = B(2, 0); 438 i->rn = B(5, 3); 439 if(B(6, 6)) 440 i->rn += 8; 441 if(B(7, 7)) 442 i->rd += 8; 443 if(o != nil){ 444 if(i->w == 0x46b7 || i->w == 0x46f7 || i->w == 0x4730 || i->w == 0x4770) // mov r6, pc or mov lr, pc or bx r6 or bx lr 445 format("RET", i, ""); 446 else 447 format(o->o, i, o->a); 448 } 449 } 450 451 static void 452 thumbpcrel(Opcode *o, Instr *i) 453 { 454 int ins = i->w; 455 456 i->rn = 15; 457 i->rd = B(10, 8); 458 i->imm = 4*(B(7, 0)+1); 459 if(i->addr & 3) 460 i->imm -= 2; 461 format(o->o, i, o->a); 462 } 463 464 static void 465 thumbmovirr(Opcode *o, Instr *i) 466 { 467 int ins = i->w; 468 469 i->rd = B(2, 0); 470 i->rn = B(5, 3); 471 i->imm = B(10, 6); 472 if(strcmp(o->o, "MOVW") == 0) 473 i->imm *= 4; 474 else if(strncmp(o->o, "MOVH", 4) == 0) 475 i->imm *= 2; 476 format(o->o, i, o->a); 477 } 478 479 static void 480 thumbmovsp(Opcode *o, Instr *i) 481 { 482 int ins = i->w; 483 484 i->rn = 13; 485 i->rd = B(10, 8); 486 i->imm = 4*B(7, 0); 487 format(o->o, i, o->a); 488 } 489 490 static void 491 thumbaddsppc(Opcode *o, Instr *i) 492 { 493 int ins = i->w; 494 495 i->rd = B(10, 8); 496 i->imm = 4*B(7, 0); 497 if(i->op == 48) 498 i->imm += 4; 499 format(o->o, i, o->a); 500 } 501 502 static void 503 thumbaddsp(Opcode *o, Instr *i) 504 { 505 int ins = i->w; 506 507 i->imm = 4*B(6, 0); 508 format(o->o, i, o->a); 509 } 510 511 static void 512 thumbswi(Opcode *o, Instr *i) 513 { 514 int ins = i->w; 515 516 i->imm = B(7, 0); 517 format(o->o, i, o->a); 518 } 519 520 static void 521 thumbbcc(Opcode *o, Instr *i) 522 { 523 int off, ins = i->w; 524 525 off = B(7, 0); 526 if(off & 0x80) 527 off |= 0xffffff00; 528 i->imm = i->addr + 2*off + 4; 529 if(o != nil) 530 format(o->o, i, o->a); 531 } 532 533 static void 534 thumbb(Opcode *o, Instr *i) 535 { 536 int off, ins = i->w; 537 538 off = B(10, 0); 539 if(off & 0x400) 540 off |= 0xfffff800; 541 i->imm = i->addr + 2*off + 4; 542 if(o != nil) 543 format(o->o, i, o->a); 544 } 545 546 static void 547 thumbbl(Opcode *o, Instr *i) 548 { 549 int off, h, ins = i->w; 550 static int reglink; 551 552 h = B(11, 11); 553 off = B(10, 0); 554 if(h == 0){ 555 if(off & 0x400) 556 off |= 0xfffff800; 557 i->imm = i->addr + (off<<12) + 4; 558 reglink = i->imm; 559 } 560 else{ 561 i->imm = reglink + 2*off; 562 } 563 if(o != nil) 564 format(o->o, i, o->a); 565 } 566 567 static void 568 thumbregs(Opcode *o, Instr *i) 569 { 570 int ins = i->w; 571 572 if(i->op == 52 || i->op == 53) 573 i->rd = 13; 574 else 575 i->rd = B(10, 8); 576 i->imm = B(7, 0); 577 format(o->o, i, o->a); 578 } 579 580 static void 581 thumbunk(Opcode *o, Instr *i) 582 { 583 format(o->o, i, o->a); 584 } 585 586 static Opcode opcodes[] = 587 { 588 "LSL", thumbshift, 0, "$#%i,R%n,R%d", // 0 589 "LSR", thumbshift, 0, "$#%i,R%n,R%d", // 1 590 "ASR", thumbshift, 0, "$#%i,R%n,R%d", // 2 591 "ADD", thumbrrr, 0, "R%s,R%n,R%d", // 3 592 "SUB", thumbrrr, 0, "R%s,R%n,R%d", // 4 593 "ADD", thumbirr, 0, "$#%i,R%n,R%d", // 5 594 "SUB", thumbirr, 0, "$#%i,R%n,R%d", // 6 595 "MOVW", thumbir, 0, "$#%i,R%d", // 7 596 "CMP", thumbir, 0, "$#%i,R%d", // 8 597 "ADD", thumbir, 0, "$#%i,R%d,R%d", // 9 598 "SUB", thumbir, 0, "$#%i,R%d,R%d", // 10 599 "AND", thumbrr, 0, "R%n,R%d,R%d", // 11 600 "EOR", thumbrr, 0, "R%n,R%d,R%d", // 12 601 "LSL", thumbrr, 0, "R%n,R%d,R%d", // 13 602 "LSR", thumbrr, 0, "R%n,R%d,R%d", // 14 603 "ASR", thumbrr, 0, "R%n,R%d,R%d", // 15 604 "ADC", thumbrr, 0, "R%n,R%d,R%d", // 16 605 "SBC", thumbrr, 0, "R%n,R%d,R%d", // 17 606 "ROR", thumbrr, 0, "R%n,R%d,R%d", // 18 607 "TST", thumbrr, 0, "R%n,R%d", // 19 608 "NEG", thumbrr, 0, "R%n,R%d", // 20 609 "CMP", thumbrr, 0, "R%n,R%d", // 21 610 "CMPN", thumbrr, 0, "R%n,R%d", // 22 611 "OR", thumbrr, 0, "R%n,R%d,R%d", // 23 612 "MUL", thumbrr, 0, "R%n,R%d,R%d", // 24 613 "BITC", thumbrr, 0, "R%n,R%d,R%d", // 25 614 "MOVN", thumbrr, 0, "R%n,R%d", // 26 615 "ADD", thumbrrh, thumbfadd, "R%n,R%d,R%d", // 27 616 "CMP", thumbrrh, 0, "R%n,R%d", // 28 617 "MOVW", thumbrrh, thumbfmov, "R%n,R%d", // 29 618 "BX", thumbrrh, thumbfbranch, "R%n", // 30 619 "MOVW", thumbpcrel, 0, "$%I,R%d", // 31 620 "MOVW", thumbrrr, 0, "R%d, [R%s,R%n]", // 32 621 "MOVH", thumbrrr, 0, "R%d, [R%s,R%n]", // 33 622 "MOVB", thumbrrr, 0, "R%d, [R%s,R%n]", // 34 623 "MOVB", thumbrrr, 0, "[R%s,R%n],R%d", // 35 624 "MOVW", thumbrrr, 0, "[R%s,R%n],R%d", // 36 625 "MOVHU", thumbrrr, 0, "[R%s,R%n],R%d", // 37 626 "MOVBU", thumbrrr, 0, "[R%s,R%n],R%d", // 38 627 "MOVH", thumbrrr, 0, "[R%s,R%n],R%d", // 39 628 "MOVW", thumbmovirr, 0, "R%d,%I", // 40 629 "MOVW", thumbmovirr, 0, "%I,R%d", // 41 630 "MOVB", thumbmovirr, 0, "R%d,%I", // 42 631 "MOVBU", thumbmovirr, 0, "$%I,R%d", // 43 632 "MOVH", thumbmovirr, 0, "R%d,%I", // 44 633 "MOVHU", thumbmovirr, 0, "%I,R%d", // 45 634 "MOVW", thumbmovsp, 0, "R%d,%I", // 46 635 "MOVW", thumbmovsp, 0, "%I,R%d", // 47 636 "ADD", thumbaddsppc,0, "$#%i,PC,R%d", // 48 637 "ADD", thumbaddsppc,0, "$#%i,SP,R%d", // 49 638 "ADD", thumbaddsp, 0, "$#%i,SP,SP", // 50 639 "SUB", thumbaddsp, 0, "$#%i,SP,SP", // 51 640 "PUSH", thumbregs, 0, "R%d, %r", // 52 641 "POP", thumbregs, 0, "R%d, %r", // 53 642 "STMIA", thumbregs, 0, "R%d, %r", // 54 643 "LDMIA", thumbregs, 0, "R%d, %r", // 55 644 "SWI", thumbswi, 0, "$#%i", // 56 645 "B%c", thumbbcc, thumbfbranch, "%b", // 57 646 "B", thumbb, thumbfbranch, "%b", // 58 647 "BL", thumbbl, 0, "", // 59 648 "BL", thumbbl, thumbfbranch, "%b", // 60 649 "UNK", thumbunk, 0, "", // 61 650 }; 651 652 static void 653 gaddr(Instr *i) 654 { 655 *i->curr++ = '$'; 656 i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY); 657 } 658 659 static void 660 format(char *mnemonic, Instr *i, char *f) 661 { 662 int j, k, m, n; 663 int g; 664 char *fmt; 665 int ins = i->w; 666 667 if(mnemonic) 668 format(0, i, mnemonic); 669 if(f == 0) 670 return; 671 if(mnemonic) 672 if(i->curr < i->end) 673 *i->curr++ = '\t'; 674 for ( ; *f && i->curr < i->end; f++) { 675 if(*f != '%') { 676 *i->curr++ = *f; 677 continue; 678 } 679 switch (*++f) { 680 681 case 'c': /*Bcc */ 682 bprint(i, "%s", cond[B(11, 8)]); 683 break; 684 685 case 's': 686 bprint(i, "%d", i->rs); 687 break; 688 689 case 'n': 690 bprint(i, "%d", i->rn); 691 break; 692 693 case 'd': 694 bprint(i, "%d", i->rd); 695 break; 696 697 case 'i': 698 bprint(i, "%lux", i->imm); 699 break; 700 701 case 'b': 702 i->curr += symoff(i->curr, i->end-i->curr, 703 i->imm, CTEXT); 704 break; 705 706 case 'I': 707 if (i->rn == 13) { 708 if (plocal(i)) 709 break; 710 } 711 g = 0; 712 fmt = "#%lx(R%d)"; 713 if (i->rn == 15) { 714 /* convert load of offset(PC) to a load immediate */ 715 if (get4(i->map, i->addr + i->imm, &i->imm) > 0) 716 { 717 g = 1; 718 fmt = ""; 719 } 720 } 721 if (mach->sb) 722 { 723 if (i->rn == 12) 724 { 725 i->imm += mach->sb; 726 g = 1; 727 fmt = "-SB(SB)"; 728 } 729 } 730 if (g) 731 { 732 gaddr(i); 733 bprint(i, fmt, i->rn); 734 } 735 else 736 bprint(i, fmt, i->imm, i->rn); 737 break; 738 739 case 'r': 740 n = i->imm&0xff; 741 j = 0; 742 k = 0; 743 while(n) { 744 m = j; 745 while(n&0x1) { 746 j++; 747 n >>= 1; 748 } 749 if(j != m) { 750 if(k) 751 bprint(i, ","); 752 if(j == m+1) 753 bprint(i, "R%d", m); 754 else 755 bprint(i, "R%d-R%d", m, j-1); 756 k = 1; 757 } 758 j++; 759 n >>= 1; 760 } 761 break; 762 763 case '\0': 764 *i->curr++ = '%'; 765 return; 766 767 default: 768 bprint(i, "%%%c", *f); 769 break; 770 } 771 } 772 *i->curr = 0; 773 } 774 775 static int 776 printins(Map *map, ulong pc, char *buf, int n) 777 { 778 Instr i; 779 780 i.curr = buf; 781 i.end = buf+n-1; 782 if(decode(map, pc, &i) < 0) 783 return -1; 784 785 (*opcodes[i.op].fmt)(&opcodes[i.op], &i); 786 return 2; 787 } 788 789 static int 790 thumbinst(Map *map, ulong pc, char modifier, char *buf, int n) 791 { 792 USED(modifier); 793 return printins(map, pc, buf, n); 794 } 795 796 static int 797 thumbdas(Map *map, ulong pc, char *buf, int n) 798 { 799 Instr i; 800 801 i.curr = buf; 802 i.end = buf+n; 803 if(decode(map, pc, &i) < 0) 804 return -1; 805 if(i.end-i.curr > 8) 806 i.curr = _hexify(buf, i.w, 7); 807 *i.curr = 0; 808 return 2; 809 } 810 811 static int 812 thumbinstlen(Map *map, ulong pc) 813 { 814 Instr i; 815 816 if(decode(map, pc, &i) < 0) 817 return -1; 818 return 2; 819 } 820 821 static int 822 thumbfoll(Map *map, ulong pc, Rgetter rget, ulong *foll) 823 { 824 ulong d; 825 Instr i; 826 827 if(decode(map, pc, &i) < 0) 828 return -1; 829 830 if(opcodes[i.op].foll) { 831 d = (*opcodes[i.op].foll)(map, rget, &i, pc); 832 if(d == -1) 833 return -1; 834 } else 835 d = pc+2; 836 837 foll[0] = d; 838 return 1; 839 } 840