|
|
1.1 ! root 1: #include <u.h> ! 2: #include <libc.h> ! 3: #include <bio.h> ! 4: #include <mach.h> ! 5: ! 6: /* ! 7: * i386-specific debugger interface ! 8: */ ! 9: ! 10: static char *i386excep(Map*, Rgetter); ! 11: ! 12: static int i386trace(Map*, ulong, ulong, ulong, Tracer); ! 13: static ulong i386frame(Map*, ulong, ulong, ulong, ulong); ! 14: static int i386foll(Map*, ulong, Rgetter, ulong*); ! 15: static int i386inst(Map*, ulong, char, char*, int); ! 16: static int i386das(Map*, ulong, char*, int); ! 17: static int i386instlen(Map*, ulong); ! 18: ! 19: static char STARTSYM[] = "_main"; ! 20: static char PROFSYM[] = "_mainp"; ! 21: static char FRAMENAME[] = ".frame"; ! 22: static char *excname[] = ! 23: { ! 24: [0] "divide error", ! 25: [1] "debug exception", ! 26: [4] "overflow", ! 27: [5] "bounds check", ! 28: [6] "invalid opcode", ! 29: [7] "math coprocessor emulation", ! 30: [8] "double fault", ! 31: [9] "math coprocessor overrun", ! 32: [10] "invalid TSS", ! 33: [11] "segment not present", ! 34: [12] "stack exception", ! 35: [13] "general protection violation", ! 36: [14] "page fault", ! 37: [16] "math coprocessor error", ! 38: [24] "clock", ! 39: [25] "keyboard", ! 40: [27] "modem status", ! 41: [28] "serial line status", ! 42: [30] "floppy disk", ! 43: [36] "mouse", ! 44: [37] "math coprocessor", ! 45: [38] "hard disk", ! 46: [64] "system call", ! 47: }; ! 48: ! 49: Machdata i386mach = ! 50: { ! 51: {0xCC, 0, 0, 0}, /* break point: INT 3 */ ! 52: 1, /* break point size */ ! 53: ! 54: leswab, /* convert short to local byte order */ ! 55: leswal, /* convert long to local byte order */ ! 56: i386trace, /* C traceback */ ! 57: i386frame, /* frame finder */ ! 58: 0, /* ublock fixup */ ! 59: i386excep, /* print exception */ ! 60: 0, /* breakpoint fixup */ ! 61: leieeesftos, /* single precision float printer */ ! 62: leieeedftos, /* double precision float printer */ ! 63: i386foll, /* following addresses */ ! 64: i386inst, /* print instruction */ ! 65: i386das, /* dissembler */ ! 66: i386instlen, /* instruction size calculation */ ! 67: }; ! 68: ! 69: static char* ! 70: i386excep(Map *map, Rgetter rget) ! 71: { ! 72: ulong c; ! 73: ulong pc; ! 74: static char buf[16]; ! 75: ! 76: c = (*rget)(map, "TRAP"); ! 77: if(c > 64 || excname[c] == 0) { ! 78: if (c == 3) { ! 79: pc = (*rget)(map, "PC"); ! 80: if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0) ! 81: if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0) ! 82: return "breakpoint"; ! 83: } ! 84: sprint(buf, "exception %d", c); ! 85: return buf; ! 86: } else ! 87: return excname[c]; ! 88: } ! 89: ! 90: static int ! 91: i386trace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace) ! 92: { ! 93: int i; ! 94: Symbol s, f; ! 95: ulong osp; ! 96: ! 97: USED(link); ! 98: i = 0; ! 99: osp = 0; ! 100: while(findsym(pc, CTEXT, &s)) { ! 101: if(osp == sp) ! 102: break; ! 103: osp = sp; ! 104: if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) ! 105: break; ! 106: ! 107: if(pc != s.value) { /* not at first instruction */ ! 108: if(findlocal(&s, FRAMENAME, &f) == 0) ! 109: break; ! 110: sp += f.value-mach->szaddr; ! 111: } ! 112: ! 113: if (get4(map, sp, (long *) &pc) < 0) ! 114: break; ! 115: ! 116: if(pc == 0) ! 117: break; ! 118: ! 119: (*trace)(map, pc, sp, &s); ! 120: sp += mach->szaddr; ! 121: ! 122: if(++i > 40) ! 123: break; ! 124: } ! 125: return i; ! 126: } ! 127: ! 128: static ulong ! 129: i386frame(Map *map, ulong addr, ulong pc, ulong sp, ulong link) ! 130: { ! 131: Symbol s, f; ! 132: ! 133: USED(link); ! 134: while (findsym(pc, CTEXT, &s)) { ! 135: if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) ! 136: break; ! 137: ! 138: if(pc != s.value) { /* not first instruction */ ! 139: if(findlocal(&s, FRAMENAME, &f) == 0) ! 140: break; ! 141: sp += f.value-mach->szaddr; ! 142: } ! 143: ! 144: if (s.value == addr) ! 145: return sp; ! 146: ! 147: if (get4(map, sp, (long *)&pc) < 0) ! 148: break; ! 149: sp += mach->szaddr; ! 150: } ! 151: return 0; ! 152: } ! 153: ! 154: /* I386/486 - Disassembler and related functions */ ! 155: ! 156: /* ! 157: * an instruction ! 158: */ ! 159: typedef struct Instr Instr; ! 160: struct Instr ! 161: { ! 162: uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */ ! 163: ulong addr; /* address of start of instruction */ ! 164: int n; /* number of bytes in instruction */ ! 165: char *prefix; /* instr prefix */ ! 166: char *segment; /* segment override */ ! 167: uchar jumptype; /* set to the operand type for jump/ret/call */ ! 168: char osize; /* 'W' or 'L' */ ! 169: char asize; /* address size 'W' or 'L' */ ! 170: uchar mod; /* bits 6-7 of mod r/m field */ ! 171: uchar reg; /* bits 3-5 of mod r/m field */ ! 172: char ss; /* bits 6-7 of SIB */ ! 173: char index; /* bits 3-5 of SIB */ ! 174: char base; /* bits 0-2 of SIB */ ! 175: short seg; /* segment of far address */ ! 176: ulong disp; /* displacement */ ! 177: ulong imm; /* immediate */ ! 178: ulong imm2; /* second immediate operand */ ! 179: char *curr; /* fill level in output buffer */ ! 180: char *end; /* end of output buffer */ ! 181: char *err; /* error message */ ! 182: }; ! 183: ! 184: /* 386 register (ha!) set */ ! 185: enum{ ! 186: AX=0, ! 187: CX, ! 188: DX, ! 189: BX, ! 190: SP, ! 191: BP, ! 192: SI, ! 193: DI, ! 194: }; ! 195: /* Operand Format codes */ ! 196: /* ! 197: %A - address size register modifier (!asize -> 'E') ! 198: %C - Control register CR0/CR1/CR2 ! 199: %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7 ! 200: %I - second immediate operand ! 201: %O - Operand size register modifier (!osize -> 'E') ! 202: %T - Test register TR6/TR7 ! 203: %S - size code ('W' or 'L') ! 204: %X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE" ! 205: %d - displacement 16-32 bits ! 206: %e - effective address - Mod R/M value ! 207: %f - floating point register F0-F7 - from Mod R/M register ! 208: %g - segment register ! 209: %i - immediate operand 8-32 bits ! 210: %p - PC-relative - signed displacement in immediate field ! 211: %r - Reg from Mod R/M ! 212: %x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ" ! 213: */ ! 214: ! 215: typedef struct Optable Optable; ! 216: struct Optable ! 217: { ! 218: char operand[2]; ! 219: void *proto; /* actually either (char*) or (Optable*) */ ! 220: }; ! 221: /* Operand decoding codes */ ! 222: enum { ! 223: Ib = 1, /* 8-bit immediate - (no sign extension)*/ ! 224: Ibs, /* 8-bit immediate (sign extended) */ ! 225: Jbs, /* 8-bit sign-extended immediate in jump or call */ ! 226: Iw, /* 16-bit immediate -> imm */ ! 227: Iw2, /* 16-bit immediate -> imm2 */ ! 228: Iwd, /* Operand-sized immediate (no sign extension)*/ ! 229: Awd, /* Address offset */ ! 230: Iwds, /* Operand-sized immediate (sign extended) */ ! 231: RM, /* Word or long R/M field with register (/r) */ ! 232: RMB, /* Byte R/M field with register (/r) */ ! 233: RMOP, /* Word or long R/M field with op code (/digit) */ ! 234: RMOPB, /* Byte R/M field with op code (/digit) */ ! 235: RMR, /* R/M register only (mod = 11) */ ! 236: RMM, /* R/M memory only (mod = 0/1/2) */ ! 237: R0, /* Base reg of Mod R/M is literal 0x00 */ ! 238: R1, /* Base reg of Mod R/M is literal 0x01 */ ! 239: FRMOP, /* Floating point R/M field with opcode */ ! 240: FRMEX, /* Extended floating point R/M field with opcode */ ! 241: JUMP, /* Jump or Call flag - no operand */ ! 242: RET, /* Return flag - no operand */ ! 243: OA, /* literal 0x0a byte */ ! 244: PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ ! 245: AUX, /* Multi-byte op code - Auxiliary table */ ! 246: PRE, /* Instr Prefix */ ! 247: SEG, /* Segment Prefix */ ! 248: OPOVER, /* Operand size override */ ! 249: ADDOVER, /* Address size override */ ! 250: }; ! 251: ! 252: static Optable optab0F00[8]= ! 253: { ! 254: [0x00] 0,0, "MOVW LDT,%e", ! 255: [0x01] 0,0, "MOVW TR,%e", ! 256: [0x02] 0,0, "MOVW %e,LDT", ! 257: [0x03] 0,0, "MOVW %e,TR", ! 258: [0x04] 0,0, "VERR %e", ! 259: [0x05] 0,0, "VERW %e", ! 260: }; ! 261: ! 262: static Optable optab0F01[8]= ! 263: { ! 264: [0x00] 0,0, "MOVL GDTR,%e", ! 265: [0x01] 0,0, "MOVL IDTR,%e", ! 266: [0x02] 0,0, "MOVL %e,GDTR", ! 267: [0x03] 0,0, "MOVL %e,IDTR", ! 268: [0x04] 0,0, "MOVW MSW,%e", /* word */ ! 269: [0x06] 0,0, "MOVW %e,MSW", /* word */ ! 270: }; ! 271: ! 272: static Optable optab0FBA[8]= ! 273: { ! 274: [0x04] Ib,0, "BT%S %i,%e", ! 275: [0x05] Ib,0, "BTS%S %i,%e", ! 276: [0x06] Ib,0, "BTR%S %i,%e", ! 277: [0x07] Ib,0, "BTC%S %i,%e", ! 278: }; ! 279: ! 280: static Optable optab0F[256]= ! 281: { ! 282: [0x00] RMOP,0, optab0F00, ! 283: [0x01] RMOP,0, optab0F01, ! 284: [0x02] RM,0, "LAR %e,%r", ! 285: [0x03] RM,0, "LSL %e,%r", ! 286: [0x06] 0,0, "CLTS", ! 287: [0x08] 0,0, "INVD", ! 288: [0x09] 0,0, "WBINVD", ! 289: [0x20] RMR,0, "MOVL %C,%e", ! 290: [0x21] RMR,0, "MOVL %D,%e", ! 291: [0x22] RMR,0, "MOVL %e,%C", ! 292: [0x23] RMR,0, "MOVL %e,%D", ! 293: [0x24] RMR,0, "MOVL %T,%e", ! 294: [0x26] RMR,0, "MOVL %e,%T", ! 295: [0x30] 0,0, "WRMSR", ! 296: [0x31] 0,0, "RDTSC", ! 297: [0x32] 0,0, "RDMSR", ! 298: [0x80] Iwds,0, "JOS %p", ! 299: [0x81] Iwds,0, "JOC %p", ! 300: [0x82] Iwds,0, "JCS %p", ! 301: [0x83] Iwds,0, "JCC %p", ! 302: [0x84] Iwds,0, "JEQ %p", ! 303: [0x85] Iwds,0, "JNE %p", ! 304: [0x86] Iwds,0, "JLS %p", ! 305: [0x87] Iwds,0, "JHI %p", ! 306: [0x88] Iwds,0, "JMI %p", ! 307: [0x89] Iwds,0, "JPL %p", ! 308: [0x8a] Iwds,0, "JPS %p", ! 309: [0x8b] Iwds,0, "JPC %p", ! 310: [0x8c] Iwds,0, "JLT %p", ! 311: [0x8d] Iwds,0, "JGE %p", ! 312: [0x8e] Iwds,0, "JLE %p", ! 313: [0x8f] Iwds,0, "JGT %p", ! 314: [0x90] RMB,0, "SETOS %e", ! 315: [0x91] RMB,0, "SETOC %e", ! 316: [0x92] RMB,0, "SETCS %e", ! 317: [0x93] RMB,0, "SETCC %e", ! 318: [0x94] RMB,0, "SETEQ %e", ! 319: [0x95] RMB,0, "SETNE %e", ! 320: [0x96] RMB,0, "SETLS %e", ! 321: [0x97] RMB,0, "SETHI %e", ! 322: [0x98] RMB,0, "SETMI %e", ! 323: [0x99] RMB,0, "SETPL %e", ! 324: [0x9a] RMB,0, "SETPS %e", ! 325: [0x9b] RMB,0, "SETPC %e", ! 326: [0x9c] RMB,0, "SETLT %e", ! 327: [0x9d] RMB,0, "SETGE %e", ! 328: [0x9e] RMB,0, "SETLE %e", ! 329: [0x9f] RMB,0, "SETGT %e", ! 330: [0xa0] 0,0, "PUSHL FS", ! 331: [0xa1] 0,0, "POPL FS", ! 332: [0xa2] 0,0, "CPUID", ! 333: [0xa3] RM,0, "BT%S %r,%e", ! 334: [0xa4] RM,Ib, "SHLD%S %r,%i,%e", ! 335: [0xa5] RM,0, "SHLD%S %r,CL,%e", ! 336: [0xa8] 0,0, "PUSHL GS", ! 337: [0xa9] 0,0, "POPL GS", ! 338: [0xab] RM,0, "BTS%S %r,%e", ! 339: [0xac] RM,Ib, "SHRD%S %r,%i,%e", ! 340: [0xad] RM,0, "SHRD%S %r,CL,%e", ! 341: [0xaf] RM,0, "IMUL%S %e,%r", ! 342: [0xb2] RMM,0, "LSS %e,%r", ! 343: [0xb3] RM,0, "BTR%S %r,%e", ! 344: [0xb4] RMM,0, "LFS %e,%r", ! 345: [0xb5] RMM,0, "LGS %e,%r", ! 346: [0xb6] RMB,0, "MOVBZX %e,%R", ! 347: [0xb7] RM,0, "MOVWZX %e,%R", ! 348: [0xba] RMOP,0, optab0FBA, ! 349: [0xbb] RM,0, "BTC%S %e,%r", ! 350: [0xbc] RM,0, "BSF%S %e,%r", ! 351: [0xbd] RM,0, "BSR%S %e,%r", ! 352: [0xbe] RMB,0, "MOVBSX %e,%R", ! 353: [0xbf] RM,0, "MOVWSX %e,%R", ! 354: }; ! 355: ! 356: static Optable optab80[8]= ! 357: { ! 358: [0x00] Ib,0, "ADDB %i,%e", ! 359: [0x01] Ib,0, "ORB %i,%e", ! 360: [0x02] Ib,0, "ADCB %i,%e", ! 361: [0x03] Ib,0, "SBBB %i,%e", ! 362: [0x04] Ib,0, "ANDB %i,%e", ! 363: [0x05] Ib,0, "SUBB %i,%e", ! 364: [0x06] Ib,0, "XORB %i,%e", ! 365: [0x07] Ib,0, "CMPB %e,%i", ! 366: }; ! 367: ! 368: static Optable optab81[8]= ! 369: { ! 370: [0x00] Iwd,0, "ADD%S %i,%e", ! 371: [0x01] Iwd,0, "OR%S %i,%e", ! 372: [0x02] Iwd,0, "ADC%S %i,%e", ! 373: [0x03] Iwd,0, "SBB%S %i,%e", ! 374: [0x04] Iwd,0, "AND%S %i,%e", ! 375: [0x05] Iwd,0, "SUB%S %i,%e", ! 376: [0x06] Iwd,0, "XOR%S %i,%e", ! 377: [0x07] Iwd,0, "CMP%S %e,%i", ! 378: }; ! 379: ! 380: static Optable optab83[8]= ! 381: { ! 382: [0x00] Ibs,0, "ADD%S %i,%e", ! 383: [0x01] Ibs,0, "OR%S %i,%e", ! 384: [0x02] Ibs,0, "ADC%S %i,%e", ! 385: [0x03] Ibs,0, "SBB%S %i,%e", ! 386: [0x04] Ibs,0, "AND%S %i,%e", ! 387: [0x05] Ibs,0, "SUB%S %i,%e", ! 388: [0x06] Ibs,0, "XOR%S %i,%e", ! 389: [0x07] Ibs,0, "CMP%S %e,%i", ! 390: }; ! 391: ! 392: static Optable optabC0[8] = ! 393: { ! 394: [0x00] Ib,0, "ROLB %i,%e", ! 395: [0x01] Ib,0, "RORB %i,%e", ! 396: [0x02] Ib,0, "RCLB %i,%e", ! 397: [0x03] Ib,0, "RCRB %i,%e", ! 398: [0x04] Ib,0, "SHLB %i,%e", ! 399: [0x05] Ib,0, "SHRB %i,%e", ! 400: [0x07] Ib,0, "SARB %i,%e", ! 401: }; ! 402: ! 403: static Optable optabC1[8] = ! 404: { ! 405: [0x00] Ib,0, "ROL%S %i,%e", ! 406: [0x01] Ib,0, "ROR%S %i,%e", ! 407: [0x02] Ib,0, "RCL%S %i,%e", ! 408: [0x03] Ib,0, "RCR%S %i,%e", ! 409: [0x04] Ib,0, "SHL%S %i,%e", ! 410: [0x05] Ib,0, "SHR%S %i,%e", ! 411: [0x07] Ib,0, "SAR%S %i,%e", ! 412: }; ! 413: ! 414: static Optable optabD0[8] = ! 415: { ! 416: [0x00] 0,0, "ROLB %e", ! 417: [0x01] 0,0, "RORB %e", ! 418: [0x02] 0,0, "RCLB %e", ! 419: [0x03] 0,0, "RCRB %e", ! 420: [0x04] 0,0, "SHLB %e", ! 421: [0x05] 0,0, "SHRB %e", ! 422: [0x07] 0,0, "SARB %e", ! 423: }; ! 424: ! 425: static Optable optabD1[8] = ! 426: { ! 427: [0x00] 0,0, "ROL%S %e", ! 428: [0x01] 0,0, "ROR%S %e", ! 429: [0x02] 0,0, "RCL%S %e", ! 430: [0x03] 0,0, "RCR%S %e", ! 431: [0x04] 0,0, "SHL%S %e", ! 432: [0x05] 0,0, "SHR%S %e", ! 433: [0x07] 0,0, "SAR%S %e", ! 434: }; ! 435: ! 436: static Optable optabD2[8] = ! 437: { ! 438: [0x00] 0,0, "ROLB CL,%e", ! 439: [0x01] 0,0, "RORB CL,%e", ! 440: [0x02] 0,0, "RCLB CL,%e", ! 441: [0x03] 0,0, "RCRB CL,%e", ! 442: [0x04] 0,0, "SHLB CL,%e", ! 443: [0x05] 0,0, "SHRB CL,%e", ! 444: [0x07] 0,0, "SARB CL,%e", ! 445: }; ! 446: ! 447: static Optable optabD3[8] = ! 448: { ! 449: [0x00] 0,0, "ROL%S CL,%e", ! 450: [0x01] 0,0, "ROR%S CL,%e", ! 451: [0x02] 0,0, "RCL%S CL,%e", ! 452: [0x03] 0,0, "RCR%S CL,%e", ! 453: [0x04] 0,0, "SHL%S CL,%e", ! 454: [0x05] 0,0, "SHR%S CL,%e", ! 455: [0x07] 0,0, "SAR%S CL,%e", ! 456: }; ! 457: ! 458: static Optable optabD8[8+8] = ! 459: { ! 460: [0x00] 0,0, "FADDF %e,F0", ! 461: [0x01] 0,0, "FMULF %e,F0", ! 462: [0x02] 0,0, "FCOMF %e,F0", ! 463: [0x03] 0,0, "FCOMFP %e,F0", ! 464: [0x04] 0,0, "FSUBF %e,F0", ! 465: [0x05] 0,0, "FSUBRF %e,F0", ! 466: [0x06] 0,0, "FDIVF %e,F0", ! 467: [0x07] 0,0, "FDIVRF %e,F0", ! 468: [0x08] 0,0, "FADDD %f,F0", ! 469: [0x09] 0,0, "FMULD %f,F0", ! 470: [0x0a] 0,0, "FCOMD %f,F0", ! 471: [0x0b] 0,0, "FCOMPD %f,F0", ! 472: [0x0c] 0,0, "FSUBD %f,F0", ! 473: [0x0d] 0,0, "FSUBRD %f,F0", ! 474: [0x0e] 0,0, "FDIVD %f,F0", ! 475: [0x0f] 0,0, "FDIVRD %f,F0", ! 476: }; ! 477: /* ! 478: * optabD9 and optabDB use the following encoding: ! 479: * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07]; ! 480: * else instruction = optabDx[(modrm&0x3f)+8]; ! 481: * ! 482: * the instructions for MOD == 3, follow the 8 instructions ! 483: * for the other MOD values stored at the front of the table. ! 484: */ ! 485: static Optable optabD9[64+8] = ! 486: { ! 487: [0x00] 0,0, "FMOVF %e,F0", ! 488: [0x02] 0,0, "FMOVF F0,%e", ! 489: [0x03] 0,0, "FMOVFP F0,%e", ! 490: [0x04] 0,0, "FLDENV%S %e", ! 491: [0x05] 0,0, "FLDCW %e", ! 492: [0x06] 0,0, "FSTENV%S %e", ! 493: [0x07] 0,0, "FSTCW %e", ! 494: [0x08] 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/ ! 495: [0x09] 0,0, "FMOVD F1,F0", ! 496: [0x0a] 0,0, "FMOVD F2,F0", ! 497: [0x0b] 0,0, "FMOVD F3,F0", ! 498: [0x0c] 0,0, "FMOVD F4,F0", ! 499: [0x0d] 0,0, "FMOVD F5,F0", ! 500: [0x0e] 0,0, "FMOVD F6,F0", ! 501: [0x0f] 0,0, "FMOVD F7,F0", ! 502: [0x10] 0,0, "FXCHD F0,F0", ! 503: [0x11] 0,0, "FXCHD F1,F0", ! 504: [0x12] 0,0, "FXCHD F2,F0", ! 505: [0x13] 0,0, "FXCHD F3,F0", ! 506: [0x14] 0,0, "FXCHD F4,F0", ! 507: [0x15] 0,0, "FXCHD F5,F0", ! 508: [0x16] 0,0, "FXCHD F6,F0", ! 509: [0x17] 0,0, "FXCHD F7,F0", ! 510: [0x18] 0,0, "FNOP", ! 511: [0x28] 0,0, "FCHS", ! 512: [0x29] 0,0, "FABS", ! 513: [0x2c] 0,0, "FTST", ! 514: [0x2d] 0,0, "FXAM", ! 515: [0x30] 0,0, "FLD1", ! 516: [0x31] 0,0, "FLDL2T", ! 517: [0x32] 0,0, "FLDL2E", ! 518: [0x33] 0,0, "FLDPI", ! 519: [0x34] 0,0, "FLDLG2", ! 520: [0x35] 0,0, "FLDLN2", ! 521: [0x36] 0,0, "FLDZ", ! 522: [0x38] 0,0, "F2XM1", ! 523: [0x39] 0,0, "FYL2X", ! 524: [0x3a] 0,0, "FPTAN", ! 525: [0x3b] 0,0, "FPATAN", ! 526: [0x3c] 0,0, "FXTRACT", ! 527: [0x3d] 0,0, "FPREM1", ! 528: [0x3e] 0,0, "FDECSTP", ! 529: [0x3f] 0,0, "FNCSTP", ! 530: [0x40] 0,0, "FPREM", ! 531: [0x41] 0,0, "FYL2XP1", ! 532: [0x42] 0,0, "FSQRT", ! 533: [0x43] 0,0, "FSINCOS", ! 534: [0x44] 0,0, "FRNDINT", ! 535: [0x45] 0,0, "FSCALE", ! 536: [0x46] 0,0, "FSIN", ! 537: [0x47] 0,0, "FCOS", ! 538: }; ! 539: ! 540: static Optable optabDA[8+8] = ! 541: { ! 542: [0x00] 0,0, "FADDL %e,F0", ! 543: [0x01] 0,0, "FMULL %e,F0", ! 544: [0x02] 0,0, "FCOML %e,F0", ! 545: [0x03] 0,0, "FCOMLP %e,F0", ! 546: [0x04] 0,0, "FSUBL %e,F0", ! 547: [0x05] 0,0, "FSUBRL %e,F0", ! 548: [0x06] 0,0, "FDIVL %e,F0", ! 549: [0x07] 0,0, "FDIVRL %e,F0", ! 550: [0x0d] R1,0, "FUCOMPP", ! 551: }; ! 552: ! 553: static Optable optabDB[8+64] = ! 554: { ! 555: [0x00] 0,0, "FMOVL %e,F0", ! 556: [0x02] 0,0, "FMOVL F0,%e", ! 557: [0x03] 0,0, "FMOVLP F0,%e", ! 558: [0x05] 0,0, "FMOVX %e,F0", ! 559: [0x07] 0,0, "FMOVXP F0,%e", ! 560: [0x2a] 0,0, "FCLEX", ! 561: [0x2b] 0,0, "FINIT", ! 562: }; ! 563: ! 564: static Optable optabDC[8+8] = ! 565: { ! 566: [0x00] 0,0, "FADDD %e,F0", ! 567: [0x01] 0,0, "FMULD %e,F0", ! 568: [0x02] 0,0, "FCOMD %e,F0", ! 569: [0x03] 0,0, "FCOMDP %e,F0", ! 570: [0x04] 0,0, "FSUBD %e,F0", ! 571: [0x05] 0,0, "FSUBRD %e,F0", ! 572: [0x06] 0,0, "FDIVD %e,F0", ! 573: [0x07] 0,0, "FDIVRD %e,F0", ! 574: [0x08] 0,0, "FADDD F0,%f", ! 575: [0x09] 0,0, "FMULD F0,%f", ! 576: [0x0c] 0,0, "FSUBRD F0,%f", ! 577: [0x0d] 0,0, "FSUBD F0,%f", ! 578: [0x0e] 0,0, "FDIVRD F0,%f", ! 579: [0x0f] 0,0, "FDIVD F0,%f", ! 580: }; ! 581: ! 582: static Optable optabDD[8+8] = ! 583: { ! 584: [0x00] 0,0, "FMOVD %e,F0", ! 585: [0x02] 0,0, "FMOVD F0,%e", ! 586: [0x03] 0,0, "FMOVDP F0,%e", ! 587: [0x04] 0,0, "FRSTOR%S %e", ! 588: [0x06] 0,0, "FSAVE%S %e", ! 589: [0x07] 0,0, "FSTSW %e", ! 590: [0x08] 0,0, "FFREED %f", ! 591: [0x0a] 0,0, "FMOVD %f,F0", ! 592: [0x0b] 0,0, "FMOVDP %f,F0", ! 593: [0x0c] 0,0, "FUCOMD %f,F0", ! 594: [0x0d] 0,0, "FUCOMDP %f,F0", ! 595: }; ! 596: ! 597: static Optable optabDE[8+8] = ! 598: { ! 599: [0x00] 0,0, "FADDW %e,F0", ! 600: [0x01] 0,0, "FMULW %e,F0", ! 601: [0x02] 0,0, "FCOMW %e,F0", ! 602: [0x03] 0,0, "FCOMWP %e,F0", ! 603: [0x04] 0,0, "FSUBW %e,F0", ! 604: [0x05] 0,0, "FSUBRW %e,F0", ! 605: [0x06] 0,0, "FDIVW %e,F0", ! 606: [0x07] 0,0, "FDIVRW %e,F0", ! 607: [0x08] 0,0, "FADDDP F0,%f", ! 608: [0x09] 0,0, "FMULDP F0,%f", ! 609: [0x0b] R1,0, "FCOMPDP", ! 610: [0x0c] 0,0, "FSUBRDP F0,%f", ! 611: [0x0d] 0,0, "FSUBDP F0,%f", ! 612: [0x0e] 0,0, "FDIVRDP F0,%f", ! 613: [0x0f] 0,0, "FDIVDP F0,%f", ! 614: }; ! 615: ! 616: static Optable optabDF[8+8] = ! 617: { ! 618: [0x00] 0,0, "FMOVW %e,F0", ! 619: [0x02] 0,0, "FMOVW F0,%e", ! 620: [0x03] 0,0, "FMOVWP F0,%e", ! 621: [0x04] 0,0, "FBLD %e", ! 622: [0x05] 0,0, "FMOVL %e,F0", ! 623: [0x06] 0,0, "FBSTP %e", ! 624: [0x07] 0,0, "FMOVLP F0,%e", ! 625: [0x0c] R0,0, "FSTSW %OAX", ! 626: }; ! 627: ! 628: static Optable optabF6[8] = ! 629: { ! 630: [0x00] Ib,0, "TESTB %i,%e", ! 631: [0x02] 0,0, "NOTB %e", ! 632: [0x03] 0,0, "NEGB %e", ! 633: [0x04] 0,0, "MULB AL,%e", ! 634: [0x05] 0,0, "IMULB AL,%e", ! 635: [0x06] 0,0, "DIVB AL,%e", ! 636: [0x07] 0,0, "IDIVB AL,%e", ! 637: }; ! 638: ! 639: static Optable optabF7[8] = ! 640: { ! 641: [0x00] Iwd,0, "TEST%S %i,%e", ! 642: [0x02] 0,0, "NOT%S %e", ! 643: [0x03] 0,0, "NEG%S %e", ! 644: [0x04] 0,0, "MUL%S %OAX,%e", ! 645: [0x05] 0,0, "IMUL%S %OAX,%e", ! 646: [0x06] 0,0, "DIV%S %OAX,%e", ! 647: [0x07] 0,0, "IDIV%S %OAX,%e", ! 648: }; ! 649: ! 650: static Optable optabFE[8] = ! 651: { ! 652: [0x00] 0,0, "INCB %e", ! 653: [0x01] 0,0, "DECB %e", ! 654: }; ! 655: ! 656: static Optable optabFF[8] = ! 657: { ! 658: [0x00] 0,0, "INC%S %e", ! 659: [0x01] 0,0, "DEC%S %e", ! 660: [0x02] JUMP,0, "CALL*%S %e", ! 661: [0x03] JUMP,0, "CALLF*%S %e", ! 662: [0x04] JUMP,0, "JMP*%S %e", ! 663: [0x05] JUMP,0, "JMPF*%S %e", ! 664: [0x06] 0,0, "PUSHL %e", ! 665: }; ! 666: ! 667: static Optable optable[256] = ! 668: { ! 669: [0x00] RMB,0, "ADDB %r,%e", ! 670: [0x01] RM,0, "ADD%S %r,%e", ! 671: [0x02] RMB,0, "ADDB %e,%r", ! 672: [0x03] RM,0, "ADD%S %e,%r", ! 673: [0x04] Ib,0, "ADDB %i,AL", ! 674: [0x05] Iwd,0, "ADD%S %i,%OAX", ! 675: [0x06] 0,0, "PUSHL ES", ! 676: [0x07] 0,0, "POPL ES", ! 677: [0x08] RMB,0, "ORB %r,%e", ! 678: [0x09] RM,0, "OR%S %r,%e", ! 679: [0x0a] RMB,0, "ORB %e,%r", ! 680: [0x0b] RM,0, "OR%S %e,%r", ! 681: [0x0c] Ib,0, "ORB %i,AL", ! 682: [0x0d] Iwd,0, "OR%S %i,%OAX", ! 683: [0x0e] 0,0, "PUSHL CS", ! 684: [0x0f] AUX,0, optab0F, ! 685: [0x10] RMB,0, "ADCB %r,%e", ! 686: [0x11] RM,0, "ADC%S %r,%e", ! 687: [0x12] RMB,0, "ADCB %e,%r", ! 688: [0x13] RM,0, "ADC%S %e,%r", ! 689: [0x14] Ib,0, "ADCB %i,AL", ! 690: [0x15] Iwd,0, "ADC%S %i,%OAX", ! 691: [0x16] 0,0, "PUSHL SS", ! 692: [0x17] 0,0, "POPL SS", ! 693: [0x18] RMB,0, "SBBB %r,%e", ! 694: [0x19] RM,0, "SBB%S %r,%e", ! 695: [0x1a] RMB,0, "SBBB %e,%r", ! 696: [0x1b] RM,0, "SBB%S %e,%r", ! 697: [0x1c] Ib,0, "SBBB %i,AL", ! 698: [0x1d] Iwd,0, "SBB%S %i,%OAX", ! 699: [0x1e] 0,0, "PUSHL DS", ! 700: [0x1f] 0,0, "POPL DS", ! 701: [0x20] RMB,0, "ANDB %r,%e", ! 702: [0x21] RM,0, "AND%S %r,%e", ! 703: [0x22] RMB,0, "ANDB %e,%r", ! 704: [0x23] RM,0, "AND%S %e,%r", ! 705: [0x24] Ib,0, "ANDB %i,AL", ! 706: [0x25] Iwd,0, "AND%S %i,%OAX", ! 707: [0x26] SEG,0, "ES:", ! 708: [0x27] 0,0, "DAA", ! 709: [0x28] RMB,0, "SUBB %r,%e", ! 710: [0x29] RM,0, "SUB%S %r,%e", ! 711: [0x2a] RMB,0, "SUBB %e,%r", ! 712: [0x2b] RM,0, "SUB%S %e,%r", ! 713: [0x2c] Ib,0, "SUBB %i,AL", ! 714: [0x2d] Iwd,0, "SUB%S %i,%OAX", ! 715: [0x2e] SEG,0, "CS:", ! 716: [0x2f] 0,0, "DAS", ! 717: [0x30] RMB,0, "XORB %r,%e", ! 718: [0x31] RM,0, "XOR%S %r,%e", ! 719: [0x32] RMB,0, "XORB %e,%r", ! 720: [0x33] RM,0, "XOR%S %e,%r", ! 721: [0x34] Ib,0, "XORB %i,AL", ! 722: [0x35] Iwd,0, "XOR%S %i,%OAX", ! 723: [0x36] SEG,0, "SS:", ! 724: [0x37] 0,0, "AAA", ! 725: [0x38] RMB,0, "CMPB %r,%e", ! 726: [0x39] RM,0, "CMP%S %r,%e", ! 727: [0x3a] RMB,0, "CMPB %e,%r", ! 728: [0x3b] RM,0, "CMP%S %e,%r", ! 729: [0x3c] Ib,0, "CMPB %i,AL", ! 730: [0x3d] Iwd,0, "CMP%S %i,%OAX", ! 731: [0x3e] SEG,0, "DS:", ! 732: [0x3f] 0,0, "AAS", ! 733: [0x40] 0,0, "INC%S %OAX", ! 734: [0x41] 0,0, "INC%S %OCX", ! 735: [0x42] 0,0, "INC%S %ODX", ! 736: [0x43] 0,0, "INC%S %OBX", ! 737: [0x44] 0,0, "INC%S %OSP", ! 738: [0x45] 0,0, "INC%S %OBP", ! 739: [0x46] 0,0, "INC%S %OSI", ! 740: [0x47] 0,0, "INC%S %ODI", ! 741: [0x48] 0,0, "DEC%S %OAX", ! 742: [0x49] 0,0, "DEC%S %OCX", ! 743: [0x4a] 0,0, "DEC%S %ODX", ! 744: [0x4b] 0,0, "DEC%S %OBX", ! 745: [0x4c] 0,0, "DEC%S %OSP", ! 746: [0x4d] 0,0, "DEC%S %OBP", ! 747: [0x4e] 0,0, "DEC%S %OSI", ! 748: [0x4f] 0,0, "DEC%S %ODI", ! 749: [0x50] 0,0, "PUSH%S %OAX", ! 750: [0x51] 0,0, "PUSH%S %OCX", ! 751: [0x52] 0,0, "PUSH%S %ODX", ! 752: [0x53] 0,0, "PUSH%S %OBX", ! 753: [0x54] 0,0, "PUSH%S %OSP", ! 754: [0x55] 0,0, "PUSH%S %OBP", ! 755: [0x56] 0,0, "PUSH%S %OSI", ! 756: [0x57] 0,0, "PUSH%S %ODI", ! 757: [0x58] 0,0, "POP%S %OAX", ! 758: [0x59] 0,0, "POP%S %OCX", ! 759: [0x5a] 0,0, "POP%S %ODX", ! 760: [0x5b] 0,0, "POP%S %OBX", ! 761: [0x5c] 0,0, "POP%S %OSP", ! 762: [0x5d] 0,0, "POP%S %OBP", ! 763: [0x5e] 0,0, "POP%S %OSI", ! 764: [0x5f] 0,0, "POP%S %ODI", ! 765: [0x60] 0,0, "PUSHA%S", ! 766: [0x61] 0,0, "POPA%S", ! 767: [0x62] RMM,0, "BOUND %e,%r", ! 768: [0x63] RM,0, "ARPL %r,%e", ! 769: [0x64] SEG,0, "FS:", ! 770: [0x65] SEG,0, "GS:", ! 771: [0x66] OPOVER,0, "", ! 772: [0x67] ADDOVER,0, "", ! 773: [0x68] Iwd,0, "PUSH%S %i", ! 774: [0x69] RM,Iwd, "IMUL%S %e,%i,%r", ! 775: [0x6a] Ib,0, "PUSH%S %i", ! 776: [0x6b] RM,Ibs, "IMUL%S %e,%i,%r", ! 777: [0x6c] 0,0, "INSB DX,(%ODI)", ! 778: [0x6d] 0,0, "INS%S DX,(%ODI)", ! 779: [0x6e] 0,0, "OUTSB (%ASI),DX", ! 780: [0x6f] 0,0, "OUTS%S (%ASI),DX", ! 781: [0x70] Jbs,0, "JOS %p", ! 782: [0x71] Jbs,0, "JOC %p", ! 783: [0x72] Jbs,0, "JCS %p", ! 784: [0x73] Jbs,0, "JCC %p", ! 785: [0x74] Jbs,0, "JEQ %p", ! 786: [0x75] Jbs,0, "JNE %p", ! 787: [0x76] Jbs,0, "JLS %p", ! 788: [0x77] Jbs,0, "JHI %p", ! 789: [0x78] Jbs,0, "JMI %p", ! 790: [0x79] Jbs,0, "JPL %p", ! 791: [0x7a] Jbs,0, "JPS %p", ! 792: [0x7b] Jbs,0, "JPC %p", ! 793: [0x7c] Jbs,0, "JLT %p", ! 794: [0x7d] Jbs,0, "JGE %p", ! 795: [0x7e] Jbs,0, "JLE %p", ! 796: [0x7f] Jbs,0, "JGT %p", ! 797: [0x80] RMOPB,0, optab80, ! 798: [0x81] RMOP,0, optab81, ! 799: [0x83] RMOP,0, optab83, ! 800: [0x84] RMB,0, "TESTB %r,%e", ! 801: [0x85] RM,0, "TEST%S %r,%e", ! 802: [0x86] RMB,0, "XCHGB %r,%e", ! 803: [0x87] RM,0, "XCHG%S %r,%e", ! 804: [0x88] RMB,0, "MOVB %r,%e", ! 805: [0x89] RM,0, "MOV%S %r,%e", ! 806: [0x8a] RMB,0, "MOVB %e,%r", ! 807: [0x8b] RM,0, "MOV%S %e,%r", ! 808: [0x8c] RM,0, "MOVW %g,%e", ! 809: [0x8d] RM,0, "LEA %e,%r", ! 810: [0x8e] RM,0, "MOVW %e,%g", ! 811: [0x8f] RM,0, "POP%S %e", ! 812: [0x90] 0,0, "NOP", ! 813: [0x91] 0,0, "XCHG %OCX,%OAX", ! 814: [0x92] 0,0, "XCHG %OCX,%OAX", ! 815: [0x93] 0,0, "XCHG %OCX,%OAX", ! 816: [0x94] 0,0, "XCHG %OSP,%OAX", ! 817: [0x95] 0,0, "XCHG %OBP,%OAX", ! 818: [0x96] 0,0, "XCHG %OSI,%OAX", ! 819: [0x97] 0,0, "XCHG %ODI,%OAX", ! 820: [0x98] 0,0, "%X", /* miserable CBW or CWDE */ ! 821: [0x99] 0,0, "%x", /* idiotic CWD or CDQ */ ! 822: [0x9a] PTR,0, "CALL%S %d", ! 823: [0x9b] 0,0, "WAIT", ! 824: [0x9c] 0,0, "PUSH FLAGS", ! 825: [0x9d] 0,0, "POP FLAGS", ! 826: [0x9f] 0,0, "LAHF", ! 827: [0xa0] Awd,0, "MOVB %i,AL", ! 828: [0xa1] Awd,0, "MOV%S %i,%OAX", ! 829: [0xa2] Awd,0, "MOVB AL,%i", ! 830: [0xa3] Awd,0, "MOV%S %OAX,%i", ! 831: [0xa4] 0,0, "MOVSB (%ASI),(%ADI)", ! 832: [0xa5] 0,0, "MOVS%S (%ASI),(%ADI)", ! 833: [0xa6] 0,0, "CMPSB (%ASI),(%ADI)", ! 834: [0xa7] 0,0, "CMPS%S (%ASI),(%ADI)", ! 835: [0xa8] Ib,0, "TESTB %i,AL", ! 836: [0xa9] Iwd,0, "TEST%S %i,%OAX", ! 837: [0xaa] 0,0, "STOSB AL,(%ADI)", ! 838: [0xab] 0,0, "STOS%S %OAX,(%ADI)", ! 839: [0xac] 0,0, "LODSB (%ASI),AL", ! 840: [0xad] 0,0, "LODS%S (%ASI),%OAX", ! 841: [0xae] 0,0, "SCASB (%ADI),AL", ! 842: [0xaf] 0,0, "SCAS%S (%ADI),%OAX", ! 843: [0xb0] Ib,0, "MOVB %i,AL", ! 844: [0xb1] Ib,0, "MOVB %i,CL", ! 845: [0xb2] Ib,0, "MOVB %i,DL", ! 846: [0xb3] Ib,0, "MOVB %i,BL", ! 847: [0xb4] Ib,0, "MOVB %i,AH", ! 848: [0xb5] Ib,0, "MOVB %i,CH", ! 849: [0xb6] Ib,0, "MOVB %i,DH", ! 850: [0xb7] Ib,0, "MOVB %i,BH", ! 851: [0xb8] Iwd,0, "MOV%S %i,%OAX", ! 852: [0xb9] Iwd,0, "MOV%S %i,%OCX", ! 853: [0xba] Iwd,0, "MOV%S %i,%ODX", ! 854: [0xbb] Iwd,0, "MOV%S %i,%OBX", ! 855: [0xbc] Iwd,0, "MOV%S %i,%OSP", ! 856: [0xbd] Iwd,0, "MOV%S %i,%OBP", ! 857: [0xbe] Iwd,0, "MOV%S %i,%OSI", ! 858: [0xbf] Iwd,0, "MOV%S %i,%ODI", ! 859: [0xc0] RMOPB,0, optabC0, ! 860: [0xc1] RMOP,0, optabC1, ! 861: [0xc2] Iw,0, "RET %i", ! 862: [0xc3] RET,0, "RET", ! 863: [0xc4] RM,0, "LES %e,%r", ! 864: [0xc5] RM,0, "LDS %e,%r", ! 865: [0xc6] RMB,Ib, "MOVB %i,%e", ! 866: [0xc7] RM,Iwd, "MOV%S %i,%e", ! 867: [0xc8] Iw2,Ib, "ENTER %i,%I", /* loony ENTER */ ! 868: [0xc9] RET,0, "LEAVE", /* bizarre LEAVE */ ! 869: [0xca] Iw,0, "RETF %i", ! 870: [0xcb] RET,0, "RETF", ! 871: [0xcc] 0,0, "INT 3", ! 872: [0xcd] Ib,0, "INTB %i", ! 873: [0xce] 0,0, "INTO", ! 874: [0xcf] 0,0, "IRET", ! 875: [0xd0] RMOPB,0, optabD0, ! 876: [0xd1] RMOP,0, optabD1, ! 877: [0xd2] RMOPB,0, optabD2, ! 878: [0xd3] RMOP,0, optabD3, ! 879: [0xd4] OA,0, "AAM", ! 880: [0xd5] OA,0, "AAD", ! 881: [0xd7] 0,0, "XLAT", ! 882: [0xd8] FRMOP,0, optabD8, ! 883: [0xd9] FRMEX,0, optabD9, ! 884: [0xda] FRMOP,0, optabDA, ! 885: [0xdb] FRMEX,0, optabDB, ! 886: [0xdc] FRMOP,0, optabDC, ! 887: [0xdd] FRMOP,0, optabDD, ! 888: [0xde] FRMOP,0, optabDE, ! 889: [0xdf] FRMOP,0, optabDF, ! 890: [0xe0] Jbs,0, "LOOPNE %p", ! 891: [0xe1] Jbs,0, "LOOPE %p", ! 892: [0xe2] Jbs,0, "LOOP %p", ! 893: [0xe3] Jbs,0, "JCXZ %p", ! 894: [0xe4] Ib,0, "INB %i,AL", ! 895: [0xe5] Ib,0, "IN%S %i,%OAX", ! 896: [0xe6] Ib,0, "OUTB AL,%i", ! 897: [0xe7] Ib,0, "OUT%S %OAX,%i", ! 898: [0xe8] Iwds,0, "CALL %p", ! 899: [0xe9] Iwds,0, "JMP %p", ! 900: [0xea] PTR,0, "JMP %d", ! 901: [0xeb] Jbs,0, "JMP %p", ! 902: [0xec] 0,0, "INB DX,AL", ! 903: [0xed] 0,0, "IN%S DX,%OAX", ! 904: [0xee] 0,0, "OUTB AL,DX", ! 905: [0xef] 0,0, "OUT%S %OAX,DX", ! 906: [0xf0] PRE,0, "LOCK", ! 907: [0xf2] PRE,0, "REPNE", ! 908: [0xf3] PRE,0, "REP", ! 909: [0xf4] 0,0, "HALT", ! 910: [0xf5] 0,0, "CMC", ! 911: [0xf6] RMOPB,0, optabF6, ! 912: [0xf7] RMOP,0, optabF7, ! 913: [0xf8] 0,0, "CLC", ! 914: [0xf9] 0,0, "STC", ! 915: [0xfa] 0,0, "CLI", ! 916: [0xfb] 0,0, "STI", ! 917: [0xfc] 0,0, "CLD", ! 918: [0xfd] 0,0, "STD", ! 919: [0xfe] RMOPB,0, optabFE, ! 920: [0xff] RMOP,0, optabFF, ! 921: }; ! 922: ! 923: /* ! 924: * get a byte of the instruction ! 925: */ ! 926: static int ! 927: igetc(Map * map, Instr *ip, uchar *c) ! 928: { ! 929: if(ip->n+1 > sizeof(ip->mem)){ ! 930: werrstr("instruction too long"); ! 931: return -1; ! 932: } ! 933: if (get1(map, ip->addr+ip->n, c, 1) < 0) { ! 934: werrstr("can't read instruction: %r"); ! 935: return -1; ! 936: } ! 937: ip->mem[ip->n++] = *c; ! 938: return 1; ! 939: } ! 940: ! 941: /* ! 942: * get two bytes of the instruction ! 943: */ ! 944: static int ! 945: igets(Map *map, Instr *ip, ushort *sp) ! 946: { ! 947: uchar c; ! 948: ushort s; ! 949: ! 950: if (igetc(map, ip, &c) < 0) ! 951: return -1; ! 952: s = c; ! 953: if (igetc(map, ip, &c) < 0) ! 954: return -1; ! 955: s |= (c<<8); ! 956: *sp = s; ! 957: return 1; ! 958: } ! 959: ! 960: /* ! 961: * get 4 bytes of the instruction ! 962: */ ! 963: static int ! 964: igetl(Map *map, Instr *ip, ulong *lp) ! 965: { ! 966: ushort s; ! 967: long l; ! 968: ! 969: if (igets(map, ip, &s) < 0) ! 970: return -1; ! 971: l = s; ! 972: if (igets(map, ip, &s) < 0) ! 973: return -1; ! 974: l |= (s<<16); ! 975: *lp = l; ! 976: return 1; ! 977: } ! 978: ! 979: static int ! 980: getdisp(Map *map, Instr *ip, int mod, int rm, int code) ! 981: { ! 982: uchar c; ! 983: ushort s; ! 984: ! 985: if (mod > 2) ! 986: return 1; ! 987: if (mod == 1) { ! 988: if (igetc(map, ip, &c) < 0) ! 989: return -1; ! 990: if (c&0x80) ! 991: ip->disp = c|0xffffff00; ! 992: else ! 993: ip->disp = c&0xff; ! 994: } else if (mod == 2 || rm == code) { ! 995: if (ip->asize == 'E') { ! 996: if (igetl(map, ip, &ip->disp) < 0) ! 997: return -1; ! 998: } else { ! 999: if (igets(map, ip, &s) < 0) ! 1000: return -1; ! 1001: if (s&0x8000) ! 1002: ip->disp = s|0xffff0000; ! 1003: else ! 1004: ip->disp = s; ! 1005: } ! 1006: if (mod == 0) ! 1007: ip->base = -1; ! 1008: } ! 1009: return 1; ! 1010: } ! 1011: ! 1012: static int ! 1013: modrm(Map *map, Instr *ip, uchar c) ! 1014: { ! 1015: uchar rm, mod; ! 1016: ! 1017: mod = (c>>6)&3; ! 1018: rm = c&7; ! 1019: ip->mod = mod; ! 1020: ip->base = rm; ! 1021: ip->reg = (c>>3)&7; ! 1022: if (mod == 3) /* register */ ! 1023: return 1; ! 1024: if (ip->asize == 0) { /* 16-bit mode */ ! 1025: switch(rm) ! 1026: { ! 1027: case 0: ! 1028: ip->base = BX; ip->index = SI; ! 1029: break; ! 1030: case 1: ! 1031: ip->base = BX; ip->index = DI; ! 1032: break; ! 1033: case 2: ! 1034: ip->base = BP; ip->index = SI; ! 1035: break; ! 1036: case 3: ! 1037: ip->base = BP; ip->index = DI; ! 1038: break; ! 1039: case 4: ! 1040: ip->base = SI; ! 1041: break; ! 1042: case 5: ! 1043: ip->base = DI; ! 1044: break; ! 1045: case 6: ! 1046: ip->base = BP; ! 1047: break; ! 1048: case 7: ! 1049: ip->base = BX; ! 1050: break; ! 1051: default: ! 1052: break; ! 1053: } ! 1054: return getdisp(map, ip, mod, rm, 6); ! 1055: } ! 1056: if (rm == 4) { /* scummy sib byte */ ! 1057: if (igetc(map, ip, &c) < 0) ! 1058: return -1; ! 1059: ip->ss = (c>>6)&0x03; ! 1060: ip->index = (c>>3)&0x07; ! 1061: if (ip->index == 4) ! 1062: ip->index = -1; ! 1063: ip->base = c&0x07; ! 1064: return getdisp(map, ip, mod, ip->base, 5); ! 1065: } ! 1066: return getdisp(map, ip, mod, rm, 5); ! 1067: } ! 1068: ! 1069: static Optable * ! 1070: mkinstr(Map *map, Instr *ip, ulong pc) ! 1071: { ! 1072: int i, n; ! 1073: uchar c; ! 1074: ushort s; ! 1075: Optable *op, *obase; ! 1076: char buf[128]; ! 1077: ! 1078: memset(ip, 0, sizeof(*ip)); ! 1079: ip->base = -1; ! 1080: ip->index = -1; ! 1081: if(asstype == AI8086) ! 1082: ip->osize = 'W'; ! 1083: else { ! 1084: ip->osize = 'L'; ! 1085: ip->asize = 'E'; ! 1086: } ! 1087: ip->addr = pc; ! 1088: if (igetc(map, ip, &c) < 0) ! 1089: return 0; ! 1090: obase = optable; ! 1091: newop: ! 1092: op = &obase[c]; ! 1093: if (op->proto == 0) { ! 1094: badop: ! 1095: n = snprint(buf, sizeof(buf), "opcode: ??"); ! 1096: for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2) ! 1097: _hexify(buf+n, ip->mem[i], 1); ! 1098: strcpy(buf+n, "??"); ! 1099: werrstr(buf); ! 1100: return 0; ! 1101: } ! 1102: for(i = 0; i < 2 && op->operand[i]; i++) { ! 1103: switch(op->operand[i]) ! 1104: { ! 1105: case Ib: /* 8-bit immediate - (no sign extension)*/ ! 1106: if (igetc(map, ip, &c) < 0) ! 1107: return 0; ! 1108: ip->imm = c&0xff; ! 1109: break; ! 1110: case Jbs: /* 8-bit jump immediate (sign extended) */ ! 1111: if (igetc(map, ip, &c) < 0) ! 1112: return 0; ! 1113: if (c&0x80) ! 1114: ip->imm = c|0xffffff00; ! 1115: else ! 1116: ip->imm = c&0xff; ! 1117: ip->jumptype = Jbs; ! 1118: break; ! 1119: case Ibs: /* 8-bit immediate (sign extended) */ ! 1120: if (igetc(map, ip, &c) < 0) ! 1121: return 0; ! 1122: if (c&0x80) ! 1123: if (ip->osize == 'L') ! 1124: ip->imm = c|0xffffff00; ! 1125: else ! 1126: ip->imm = c|0xff00; ! 1127: else ! 1128: ip->imm = c&0xff; ! 1129: break; ! 1130: case Iw: /* 16-bit immediate -> imm */ ! 1131: if (igets(map, ip, &s) < 0) ! 1132: return 0; ! 1133: ip->imm = s&0xffff; ! 1134: ip->jumptype = Iw; ! 1135: break; ! 1136: case Iw2: /* 16-bit immediate -> in imm2*/ ! 1137: if (igets(map, ip, &s) < 0) ! 1138: return 0; ! 1139: ip->imm2 = s&0xffff; ! 1140: break; ! 1141: case Iwd: /* Operand-sized immediate (no sign extension)*/ ! 1142: if (ip->osize == 'L') { ! 1143: if (igetl(map, ip, &ip->imm) < 0) ! 1144: return 0; ! 1145: } else { ! 1146: if (igets(map, ip, &s)< 0) ! 1147: return 0; ! 1148: ip->imm = s&0xffff; ! 1149: } ! 1150: break; ! 1151: case Awd: /* Address-sized immediate (no sign extension)*/ ! 1152: if (ip->asize == 'E') { ! 1153: if (igetl(map, ip, &ip->imm) < 0) ! 1154: return 0; ! 1155: } else { ! 1156: if (igets(map, ip, &s)< 0) ! 1157: return 0; ! 1158: ip->imm = s&0xffff; ! 1159: } ! 1160: break; ! 1161: case Iwds: /* Operand-sized immediate (sign extended) */ ! 1162: if (ip->osize == 'L') { ! 1163: if (igetl(map, ip, &ip->imm) < 0) ! 1164: return 0; ! 1165: } else { ! 1166: if (igets(map, ip, &s)< 0) ! 1167: return 0; ! 1168: if (s&0x8000) ! 1169: ip->imm = s|0xffff0000; ! 1170: else ! 1171: ip->imm = s&0xffff; ! 1172: } ! 1173: ip->jumptype = Iwds; ! 1174: break; ! 1175: case OA: /* literal 0x0a byte */ ! 1176: if (igetc(map, ip, &c) < 0) ! 1177: return 0; ! 1178: if (c != 0x0a) ! 1179: goto badop; ! 1180: break; ! 1181: case R0: /* base register must be R0 */ ! 1182: if (ip->base != 0) ! 1183: goto badop; ! 1184: break; ! 1185: case R1: /* base register must be R1 */ ! 1186: if (ip->base != 1) ! 1187: goto badop; ! 1188: break; ! 1189: case RMB: /* R/M field with byte register (/r)*/ ! 1190: if (igetc(map, ip, &c) < 0) ! 1191: return 0; ! 1192: if (modrm(map, ip, c) < 0) ! 1193: return 0; ! 1194: ip->osize = 'B'; ! 1195: break; ! 1196: case RM: /* R/M field with register (/r) */ ! 1197: if (igetc(map, ip, &c) < 0) ! 1198: return 0; ! 1199: if (modrm(map, ip, c) < 0) ! 1200: return 0; ! 1201: break; ! 1202: case RMOPB: /* R/M field with op code (/digit) */ ! 1203: if (igetc(map, ip, &c) < 0) ! 1204: return 0; ! 1205: if (modrm(map, ip, c) < 0) ! 1206: return 0; ! 1207: c = ip->reg; /* secondary op code */ ! 1208: obase = (Optable*)op->proto; ! 1209: ip->osize = 'B'; ! 1210: goto newop; ! 1211: case RMOP: /* R/M field with op code (/digit) */ ! 1212: if (igetc(map, ip, &c) < 0) ! 1213: return 0; ! 1214: if (modrm(map, ip, c) < 0) ! 1215: return 0; ! 1216: c = ip->reg; ! 1217: obase = (Optable*)op->proto; ! 1218: goto newop; ! 1219: case FRMOP: /* FP R/M field with op code (/digit) */ ! 1220: if (igetc(map, ip, &c) < 0) ! 1221: return 0; ! 1222: if (modrm(map, ip, c) < 0) ! 1223: return 0; ! 1224: if ((c&0xc0) == 0xc0) ! 1225: c = ip->reg+8; /* 16 entry table */ ! 1226: else ! 1227: c = ip->reg; ! 1228: obase = (Optable*)op->proto; ! 1229: goto newop; ! 1230: case FRMEX: /* Extended FP R/M field with op code (/digit) */ ! 1231: if (igetc(map, ip, &c) < 0) ! 1232: return 0; ! 1233: if (modrm(map, ip, c) < 0) ! 1234: return 0; ! 1235: if ((c&0xc0) == 0xc0) ! 1236: c = (c&0x3f)+8; /* 64-entry table */ ! 1237: else ! 1238: c = ip->reg; ! 1239: obase = (Optable*)op->proto; ! 1240: goto newop; ! 1241: case RMR: /* R/M register only (mod = 11) */ ! 1242: if (igetc(map, ip, &c) < 0) ! 1243: return 0; ! 1244: if ((c&0xc0) != 0xc0) { ! 1245: werrstr("invalid R/M register: %x", c); ! 1246: return 0; ! 1247: } ! 1248: if (modrm(map, ip, c) < 0) ! 1249: return 0; ! 1250: break; ! 1251: case RMM: /* R/M register only (mod = 11) */ ! 1252: if (igetc(map, ip, &c) < 0) ! 1253: return 0; ! 1254: if ((c&0xc0) == 0xc0) { ! 1255: werrstr("invalid R/M memory mode: %x", c); ! 1256: return 0; ! 1257: } ! 1258: if (modrm(map, ip, c) < 0) ! 1259: return 0; ! 1260: break; ! 1261: case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ ! 1262: if (igets(map, ip, (ushort*)&ip->seg) < 0) ! 1263: return 0; ! 1264: if (ip->osize == 'L') { ! 1265: if (igetl(map, ip, &ip->disp) < 0) ! 1266: return 0; ! 1267: } else { ! 1268: if (igets(map, ip, &s)< 0) ! 1269: return 0; ! 1270: ip->disp = s&0xffff; ! 1271: } ! 1272: ip->jumptype = PTR; ! 1273: break; ! 1274: case AUX: /* Multi-byte op code - Auxiliary table */ ! 1275: obase = (Optable*)op->proto; ! 1276: if (igetc(map, ip, &c) < 0) ! 1277: return 0; ! 1278: goto newop; ! 1279: case PRE: /* Instr Prefix */ ! 1280: ip->prefix = (char*)op->proto; ! 1281: if (igetc(map, ip, &c) < 0) ! 1282: return 0; ! 1283: goto newop; ! 1284: case SEG: /* Segment Prefix */ ! 1285: ip->segment = (char*)op->proto; ! 1286: if (igetc(map, ip, &c) < 0) ! 1287: return 0; ! 1288: goto newop; ! 1289: case OPOVER: /* Operand size override */ ! 1290: ip->osize = 'W'; ! 1291: if (igetc(map, ip, &c) < 0) ! 1292: return 0; ! 1293: goto newop; ! 1294: case ADDOVER: /* Address size override */ ! 1295: ip->asize = 0; ! 1296: if (igetc(map, ip, &c) < 0) ! 1297: return 0; ! 1298: goto newop; ! 1299: case JUMP: /* mark instruction as JUMP or RET */ ! 1300: case RET: ! 1301: ip->jumptype = op->operand[i]; ! 1302: break; ! 1303: default: ! 1304: werrstr("bad operand type %d", op->operand[i]); ! 1305: return 0; ! 1306: } ! 1307: } ! 1308: return op; ! 1309: } ! 1310: ! 1311: static void ! 1312: bprint(Instr *ip, char *fmt, ...) ! 1313: { ! 1314: ip->curr = doprint(ip->curr, ip->end, fmt, (&fmt+1)); ! 1315: } ! 1316: ! 1317: /* ! 1318: * if 32-bit registers are to be named E<rr>, macro ANAME should ! 1319: * always return ip->asize and ONAME should return a 'E' when ! 1320: * when ip->osize == 'L'. The macros should return a null character ! 1321: * when 32-bit registers are ddesignated by <rr>. ! 1322: */ ! 1323: #define ANAME(ip) 0 ! 1324: #define ONAME(ip) ((ip)->osize == 'L' ? 0 : 0) ! 1325: ! 1326: static char *reg[] = { ! 1327: [AX] "AX", ! 1328: [CX] "CX", ! 1329: [DX] "DX", ! 1330: [BX] "BX", ! 1331: [SP] "SP", ! 1332: [BP] "BP", ! 1333: [SI] "SI", ! 1334: [DI] "DI", ! 1335: }; ! 1336: ! 1337: static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; ! 1338: static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; ! 1339: ! 1340: static void ! 1341: plocal(Instr *ip) ! 1342: { ! 1343: int ret, offset; ! 1344: Symbol s; ! 1345: char *reg; ! 1346: ! 1347: offset = ip->disp; ! 1348: if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) { ! 1349: bprint(ip, "%lux(SP)", offset); ! 1350: return; ! 1351: } ! 1352: ! 1353: if (s.value > ip->disp) { ! 1354: ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s); ! 1355: reg = "(SP)"; ! 1356: } else { ! 1357: offset -= s.value; ! 1358: ret = getauto(&s, offset, CPARAM, &s); ! 1359: reg = "(FP)"; ! 1360: } ! 1361: if (ret) ! 1362: bprint(ip, "%s+", s.name); ! 1363: else ! 1364: offset = ip->disp; ! 1365: bprint(ip, "%lux%s", offset, reg); ! 1366: } ! 1367: ! 1368: static void ! 1369: pea(Instr *ip) ! 1370: { ! 1371: if (ip->mod == 3) { ! 1372: if (ip->osize == 'B') ! 1373: bprint(ip, breg[ip->base]); ! 1374: else ! 1375: bprint(ip, "%c%s", ANAME(ip), reg[ip->base]); ! 1376: return; ! 1377: } ! 1378: if (ip->segment) ! 1379: bprint(ip, ip->segment); ! 1380: if (ip->asize == 'E' && ip->base == SP) ! 1381: plocal(ip); ! 1382: else { ! 1383: bprint(ip,"%lux", ip->disp); ! 1384: if (ip->base >= 0) ! 1385: bprint(ip,"(%c%s)", ANAME(ip), reg[ip->base]); ! 1386: } ! 1387: if (ip->index >= 0) ! 1388: bprint(ip,"(%c%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss); ! 1389: } ! 1390: ! 1391: static void ! 1392: immediate(Instr *ip, long val) ! 1393: { ! 1394: Symbol s; ! 1395: long w; ! 1396: ! 1397: if (findsym(val, CANY, &s)) { ! 1398: w = val - s.value; ! 1399: if (w < 0) ! 1400: w = -w; ! 1401: if (w < 4096) { ! 1402: if (w) ! 1403: bprint(ip, "%s+%lux(SB)", s.name, w); ! 1404: else ! 1405: bprint(ip, "%s(SB)", s.name); ! 1406: return; ! 1407: } ! 1408: } ! 1409: bprint(ip, "%lux", val); ! 1410: } ! 1411: ! 1412: static void ! 1413: prinstr(Instr *ip, char *fmt) ! 1414: { ! 1415: if (ip->prefix) ! 1416: bprint(ip, "%s ", ip->prefix); ! 1417: for (; *fmt && ip->curr < ip->end; fmt++) { ! 1418: if (*fmt != '%') ! 1419: *ip->curr++ = *fmt; ! 1420: else switch(*++fmt) ! 1421: { ! 1422: case '%': ! 1423: *ip->curr++ = '%'; ! 1424: break; ! 1425: case 'A': ! 1426: bprint(ip, "%c", ANAME(ip)); ! 1427: break; ! 1428: case 'C': ! 1429: bprint(ip, "CR%d", ip->reg); ! 1430: break; ! 1431: case 'D': ! 1432: if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7) ! 1433: bprint(ip, "DR%d",ip->reg); ! 1434: else ! 1435: bprint(ip, "???"); ! 1436: break; ! 1437: case 'I': ! 1438: bprint(ip, "$"); ! 1439: immediate(ip, ip->imm2); ! 1440: break; ! 1441: case 'O': ! 1442: bprint(ip,"%c", ONAME(ip)); ! 1443: break; ! 1444: case 'i': ! 1445: bprint(ip, "$"); ! 1446: immediate(ip,ip->imm); ! 1447: break; ! 1448: case 'R': ! 1449: bprint(ip, "%c%s", ONAME(ip), reg[ip->reg]); ! 1450: break; ! 1451: case 'S': ! 1452: bprint(ip, "%c", ip->osize); ! 1453: break; ! 1454: case 'T': ! 1455: if (ip->reg == 6 || ip->reg == 7) ! 1456: bprint(ip, "TR%d",ip->reg); ! 1457: else ! 1458: bprint(ip, "???"); ! 1459: break; ! 1460: case 'X': ! 1461: if (ip->osize == 'L') ! 1462: bprint(ip,"CWDE"); ! 1463: else ! 1464: bprint(ip, "CBW"); ! 1465: break; ! 1466: case 'd': ! 1467: bprint(ip,"%lux:%lux",ip->seg,ip->disp); ! 1468: break; ! 1469: case 'e': ! 1470: pea(ip); ! 1471: break; ! 1472: case 'f': ! 1473: bprint(ip, "F%d", ip->base); ! 1474: break; ! 1475: case 'g': ! 1476: if (ip->reg < 6) ! 1477: bprint(ip,"%s",sreg[ip->reg]); ! 1478: else ! 1479: bprint(ip,"???"); ! 1480: break; ! 1481: case 'p': ! 1482: immediate(ip, ip->imm+ip->addr+ip->n); ! 1483: break; ! 1484: case 'r': ! 1485: if (ip->osize == 'B') ! 1486: bprint(ip,"%s",breg[ip->reg]); ! 1487: else ! 1488: bprint(ip, reg[ip->reg]); ! 1489: break; ! 1490: case 'x': ! 1491: if (ip->osize == 'L') ! 1492: bprint(ip,"CDQ"); ! 1493: else ! 1494: bprint(ip, "CWD"); ! 1495: break; ! 1496: default: ! 1497: bprint(ip, "%%%c", *fmt); ! 1498: break; ! 1499: } ! 1500: } ! 1501: *ip->curr = 0; /* there's always room for 1 byte */ ! 1502: } ! 1503: ! 1504: static int ! 1505: i386inst(Map *map, ulong pc, char modifier, char *buf, int n) ! 1506: { ! 1507: Instr instr; ! 1508: Optable *op; ! 1509: ! 1510: USED(modifier); ! 1511: op = mkinstr(map, &instr, pc); ! 1512: if (op == 0) { ! 1513: if (n >= ERRLEN) ! 1514: errstr(buf); ! 1515: else ! 1516: snprint(buf,n,"%r"); ! 1517: return -1; ! 1518: } ! 1519: instr.curr = buf; ! 1520: instr.end = buf+n-1; ! 1521: prinstr(&instr, op->proto); ! 1522: return instr.n; ! 1523: } ! 1524: ! 1525: static int ! 1526: i386das(Map *map, ulong pc, char *buf, int n) ! 1527: { ! 1528: Instr instr; ! 1529: int i; ! 1530: ! 1531: if (mkinstr(map, &instr, pc) == 0) { ! 1532: if (n >= ERRLEN) ! 1533: errstr(buf); ! 1534: else ! 1535: snprint(buf,n,"%r"); ! 1536: return -1; ! 1537: } ! 1538: for(i = 0; i < instr.n && n > 2; i++) { ! 1539: _hexify(buf, instr.mem[i], 1); ! 1540: buf += 2; ! 1541: n -= 2; ! 1542: } ! 1543: *buf = 0; ! 1544: return instr.n; ! 1545: } ! 1546: ! 1547: static int ! 1548: i386instlen(Map *map, ulong pc) ! 1549: { ! 1550: Instr i; ! 1551: ! 1552: if (mkinstr(map, &i, pc)) ! 1553: return i.n; ! 1554: return -1; ! 1555: } ! 1556: ! 1557: static int ! 1558: i386foll(Map *map, ulong pc, Rgetter rget, ulong *foll) ! 1559: { ! 1560: Instr i; ! 1561: Optable *op; ! 1562: ushort s; ! 1563: ulong l, addr; ! 1564: int n; ! 1565: ! 1566: op = mkinstr(map, &i, pc); ! 1567: if (!op) ! 1568: return -1; ! 1569: ! 1570: n = 0; ! 1571: switch(i.jumptype) ! 1572: { ! 1573: case RET: /* RETURN or LEAVE */ ! 1574: case Iw: /* RETURN */ ! 1575: if (strcmp(op->proto, "LEAVE") == 0) { ! 1576: if (get4(map, (*rget)(map, "BP"), (long*)&l) < 0) ! 1577: return -1; ! 1578: } else if (get4(map, (*rget)(map, mach->sp), (long*)&l) < 0) ! 1579: return -1; ! 1580: foll[0] = l; ! 1581: return 1; ! 1582: case Iwds: /* pc relative JUMP or CALL*/ ! 1583: case Jbs: /* pc relative JUMP or CALL */ ! 1584: foll[0] = pc+i.imm+i.n; ! 1585: n = 1; ! 1586: break; ! 1587: case PTR: /* seg:displacement JUMP or CALL */ ! 1588: foll[0] = (i.seg<<4)+i.disp; ! 1589: return 1; ! 1590: case JUMP: /* JUMP or CALL EA */ ! 1591: /* calculate the effective address */ ! 1592: addr = i.disp; ! 1593: if (i.base >= 0) { ! 1594: if (get4(map, (*rget)(map, reg[i.base]), (long*)&l) < 0) ! 1595: return -1; ! 1596: addr += l; ! 1597: } ! 1598: if (i.index >= 0) { ! 1599: if (get4(map, (*rget)(map, reg[i.index]), (long*)&l) < 0) ! 1600: return -1; ! 1601: addr += l*(1<<i.ss); ! 1602: } ! 1603: /* now retrieve a seg:disp value at that address */ ! 1604: if (get2(map, addr, &s) < 0) /* seg */ ! 1605: return -1; ! 1606: foll[0] = s<<4; ! 1607: addr += 2; ! 1608: if (i.asize == 'L') { ! 1609: if (get4(map, addr, (long*)&l) < 0) /* disp32 */ ! 1610: return -1; ! 1611: foll[0] += l; ! 1612: } else { /* disp16 */ ! 1613: if (get2(map, addr, &s) < 0) ! 1614: return -1; ! 1615: foll[0] += s; ! 1616: } ! 1617: return 1; ! 1618: default: ! 1619: break; ! 1620: } ! 1621: if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0) ! 1622: return 1; ! 1623: foll[n++] = pc+i.n; ! 1624: return n; ! 1625: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.