/** * Disassembles a block of memory. * * @returns VBox status code. * @param argv0 Program name (for errors and warnings). * @param enmCpuMode The cpu mode to disassemble in. * @param uAddress The address we're starting to disassemble at. * @param uHighlightAddr The address of the instruction that should be * highlighted. Pass UINT64_MAX to keep quiet. * @param pbFile Where to start disassemble. * @param cbFile How much to disassemble. * @param enmStyle The assembly output style. * @param fListing Whether to print in a listing like mode. * @param enmUndefOp How to deal with undefined opcodes. */ static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress, uint64_t uHighlightAddr, uint8_t *pbFile, size_t cbFile, ASMSTYLE enmStyle, bool fListing, UNDEFOPHANDLING enmUndefOp) { /* * Initialize the CPU context. */ MYDISSTATE State; State.uAddress = uAddress; State.pbInstr = pbFile; State.cbInstr = 0; State.enmUndefOp = enmUndefOp; State.rc = VINF_SUCCESS; State.cbLeft = cbFile; State.pbNext = pbFile; State.uNextAddr = uAddress; void (*pfnFormatter)(PMYDISSTATE pState); switch (enmStyle) { case kAsmStyle_Default: pfnFormatter = MyDisasDefaultFormatter; break; case kAsmStyle_yasm: RTPrintf(" BITS %d\n", enmCpuMode == DISCPUMODE_16BIT ? 16 : enmCpuMode == DISCPUMODE_32BIT ? 32 : 64); pfnFormatter = MyDisasYasmFormatter; break; case kAsmStyle_masm: pfnFormatter = MyDisasMasmFormatter; break; default: AssertFailedReturn(VERR_INTERNAL_ERROR); } /* * The loop. */ int rcRet = VINF_SUCCESS; while (State.cbLeft > 0) { /* * Disassemble it. */ State.cbInstr = 0; State.cbLeft += State.pbNext - State.pbInstr; State.uNextAddr = State.uAddress; State.pbNext = State.pbInstr; int rc = DISInstrToStrWithReader(State.uAddress, enmCpuMode, MyDisasInstrRead, &State, &State.Dis, &State.cbInstr, State.szLine, sizeof(State.szLine)); if ( RT_SUCCESS(rc) || ( ( rc == VERR_DIS_INVALID_OPCODE || rc == VERR_DIS_GEN_FAILURE) && State.enmUndefOp == kUndefOp_DefineByte)) { State.fUndefOp = rc == VERR_DIS_INVALID_OPCODE || rc == VERR_DIS_GEN_FAILURE || State.Dis.pCurInstr->uOpcode == OP_INVALID || State.Dis.pCurInstr->uOpcode == OP_ILLUD2 || ( State.enmUndefOp == kUndefOp_DefineByte && !MyDisasIsValidInstruction(&State.Dis)); if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte) { if (!State.cbInstr) { State.Dis.abInstr[0] = 0; State.Dis.pfnReadBytes(&State.Dis, 0, 1, 1); State.cbInstr = 1; } RTPrintf(" db"); for (unsigned off = 0; off < State.cbInstr; off++) RTPrintf(off ? ", %03xh" : " %03xh", State.Dis.abInstr[off]); RTPrintf(" ; %s\n", State.szLine); } else if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All) { RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Dis.pCurInstr->uOpcode); pfnFormatter(&State); rcRet = VERR_GENERAL_FAILURE; } else if (State.fUndefOp && State.enmUndefOp == kUndefOp_Fail) { RTPrintf("%s: error at %#RX64: undefined opcode (op=%d)\n", argv0, State.uAddress, State.Dis.pCurInstr->uOpcode); pfnFormatter(&State); rcRet = VERR_GENERAL_FAILURE; } else { /* Use db for odd encodings that we can't make the assembler use. */ if ( State.enmUndefOp == kUndefOp_DefineByte && DISFormatYasmIsOddEncoding(&State.Dis)) { RTPrintf(" db"); for (unsigned off = 0; off < State.cbInstr; off++) RTPrintf(off ? ", %03xh" : " %03xh", State.Dis.abInstr[off]); RTPrintf(" ; "); } pfnFormatter(&State); } } else { State.cbInstr = State.pbNext - State.pbInstr; if (!State.cbLeft) RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc); else if (State.cbInstr) RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr); else { RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr); if (rcRet == VINF_SUCCESS) rcRet = rc; break; } } /* Highlight this instruction? */ if (uHighlightAddr - State.uAddress < State.cbInstr) RTPrintf("; ^^^^^^^^^^^^^^^^^^^^^\n"); /* Check that the size-only mode returns the smae size on success. */ if (RT_SUCCESS(rc)) { uint32_t cbInstrOnly = 32; uint8_t abInstr[sizeof(State.Dis.abInstr)]; memcpy(abInstr, State.Dis.abInstr, sizeof(State.Dis.abInstr)); int rcOnly = DISInstrWithPrefetchedBytes(State.uAddress, enmCpuMode, 0 /*fFilter - none */, abInstr, State.Dis.cbCachedInstr, MyDisasInstrRead, &State, &State.Dis, &cbInstrOnly); if ( rcOnly != rc || cbInstrOnly != State.cbInstr) { RTPrintf("; Instruction size only check failed rc=%Rrc cbInstrOnly=%#x exepcted %Rrc and %#x\n", rcOnly, cbInstrOnly, rc, State.cbInstr); rcRet = VERR_GENERAL_FAILURE; break; } } /* next */ State.uAddress += State.cbInstr; State.pbInstr += State.cbInstr; } return rcRet; }
/** * Disassembles a block of memory. * * @returns VBox status code. * @param argv0 Program name (for errors and warnings). * @param enmCpuMode The cpu mode to disassemble in. * @param uAddress The address we're starting to disassemble at. * @param uHighlightAddr The address of the instruction that should be * highlighted. Pass UINT64_MAX to keep quiet. * @param pbFile Where to start disassemble. * @param cbFile How much to disassemble. * @param enmStyle The assembly output style. * @param fListing Whether to print in a listing like mode. * @param enmUndefOp How to deal with undefined opcodes. */ static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress, uint64_t uHighlightAddr, uint8_t *pbFile, size_t cbFile, ASMSTYLE enmStyle, bool fListing, UNDEFOPHANDLING enmUndefOp) { /* * Initialize the CPU context. */ MYDISSTATE State; State.Cpu.mode = enmCpuMode; State.Cpu.pfnReadBytes = MyDisasInstrRead; State.uAddress = uAddress; State.pbInstr = pbFile; State.cbInstr = 0; State.enmUndefOp = enmUndefOp; State.rc = VINF_SUCCESS; State.cbLeft = cbFile; State.pbNext = pbFile; State.uNextAddr = uAddress; void (*pfnFormatter)(PMYDISSTATE pState); switch (enmStyle) { case kAsmStyle_Default: pfnFormatter = MyDisasDefaultFormatter; break; case kAsmStyle_yasm: RTPrintf(" BITS %d\n", enmCpuMode == CPUMODE_16BIT ? 16 : enmCpuMode == CPUMODE_32BIT ? 32 : 64); pfnFormatter = MyDisasYasmFormatter; break; case kAsmStyle_masm: pfnFormatter = MyDisasMasmFormatter; break; default: AssertFailedReturn(VERR_INTERNAL_ERROR); } /* * The loop. */ int rcRet = VINF_SUCCESS; while (State.cbLeft > 0) { /* * Disassemble it. */ State.cbInstr = 0; State.cbLeft += State.pbNext - State.pbInstr; State.uNextAddr = State.uAddress; State.pbNext = State.pbInstr; int rc = DISInstr(&State.Cpu, State.uAddress, 0, &State.cbInstr, State.szLine); if ( RT_SUCCESS(rc) || ( ( rc == VERR_DIS_INVALID_OPCODE || rc == VERR_DIS_GEN_FAILURE) && State.enmUndefOp == kUndefOp_DefineByte)) { State.fUndefOp = rc == VERR_DIS_INVALID_OPCODE || rc == VERR_DIS_GEN_FAILURE || State.Cpu.pCurInstr->opcode == OP_INVALID || State.Cpu.pCurInstr->opcode == OP_ILLUD2 || ( State.enmUndefOp == kUndefOp_DefineByte && !MyDisasIsValidInstruction(&State.Cpu)); if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte) { RTPrintf(" db"); if (!State.cbInstr) State.cbInstr = 1; for (unsigned off = 0; off < State.cbInstr; off++) { uint8_t b; State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu); RTPrintf(off ? ", %03xh" : " %03xh", b); } RTPrintf(" ; %s\n", State.szLine); } else if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All) { RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode); pfnFormatter(&State); rcRet = VERR_GENERAL_FAILURE; } else if (State.fUndefOp && State.enmUndefOp == kUndefOp_Fail) { RTPrintf("%s: error at %#RX64: undefined opcode (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode); pfnFormatter(&State); rcRet = VERR_GENERAL_FAILURE; } else { /* Use db for odd encodings that we can't make the assembler use. */ if ( State.enmUndefOp == kUndefOp_DefineByte && MyDisasYasmFormatterIsOddEncoding(&State)) { RTPrintf(" db"); for (unsigned off = 0; off < State.cbInstr; off++) { uint8_t b; State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu); RTPrintf(off ? ", %03xh" : " %03xh", b); } RTPrintf(" ; "); } pfnFormatter(&State); } } else { State.cbInstr = State.pbNext - State.pbInstr; if (!State.cbLeft) RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc); else if (State.cbInstr) RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr); else { RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr); if (rcRet == VINF_SUCCESS) rcRet = rc; break; } } /* Highlight this instruction? */ if (uHighlightAddr - State.uAddress < State.cbInstr) RTPrintf("; ^^^^^^^^^^^^^^^^^^^^^\n"); /* next */ State.uAddress += State.cbInstr; State.pbInstr += State.cbInstr; } return rcRet; }