tstDisasm-2.cpp revision bfcfd0575ea3b853e34e5058debd5ad24693d607
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Testcase - Generic Disassembler Tool.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Copyright (C) 2008 Oracle Corporation
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * available from http://www.virtualbox.org. This file is free software;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * General Public License (GPL) as published by the Free Software
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/*******************************************************************************
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync* Header Files *
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync*******************************************************************************/
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/*******************************************************************************
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync* Structures and Typedefs *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync*******************************************************************************/
bb4f31aac6155757fe15ef9fe0bf843ed9a14441vboxsynctypedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_gas, kAsmStyle_invalid } ASMSTYLE;
bb4f31aac6155757fe15ef9fe0bf843ed9a14441vboxsynctypedef enum { kUndefOp_Fail, kUndefOp_All, kUndefOp_DefineByte, kUndefOp_End } UNDEFOPHANDLING;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsynctypedef struct MYDISSTATE
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync uint64_t uAddress; /**< The current instruction address. */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync uint8_t *pbInstr; /**< The current instruction (pointer). */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync uint32_t cbInstr; /**< The size of the current instruction. */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync bool fUndefOp; /**< Whether the current instruction is really an undefined opcode.*/
3238841f4d74fd0e37778c270ae81b177a98e21bvboxsync UNDEFOPHANDLING enmUndefOp; /**< How to treat undefined opcodes. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync size_t cbLeft; /**< The number of bytes left. (read) */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync uint64_t uNextAddr; /**< The address of the next byte. (read) */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync char szLine[256]; /**< The disassembler text output. */
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync * Default style.
abb14a9d49aa819cc2296b1daf7c416118d39f1evboxsync * @param pState The disassembler state.
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsyncstatic void MyDisasDefaultFormatter(PMYDISSTATE pState)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Yasm style.
d89903d4817e25634b9f9e877e1c54bb83886115vboxsync * @param pState The disassembler state.
9d58ed91e29fc16c33e0e8f0530a1b8c58b98462vboxsyncstatic void MyDisasYasmFormatter(PMYDISSTATE pState)
d3b1e232c566c55799a7bfc83f66b045c4d82657vboxsync /* a very quick hack. */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1));
f92fba8b6d97160b7c58689eff6c3848702bd7bavboxsync size_t cch = DISFormatYasmEx(&pState->Cpu, szTmp, sizeof(szTmp),
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync DIS_FMT_FLAGS_STRICT | DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_COMMENT
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_SPACED,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Masm style.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pState The disassembler state.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic void MyDisasMasmFormatter(PMYDISSTATE pState)
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync RTPrintf("masm not implemented: %s", pState->szLine);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * This is a temporary workaround for catching a few illegal opcodes
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * that the disassembler is currently letting thru, just enough to make
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * the assemblers happy.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * We're too close to a release to dare mess with these things now as
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * they may consequences for performance and let alone introduce bugs.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns true if it's valid. false if it isn't.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pCpu The disassembler output.
df3a016ea59e69ab2758221fd91e62a9782b144evboxsyncstatic bool MyDisasIsValidInstruction(DISCPUSTATE const *pCpu)
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync /* These doesn't take memory operands. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return false;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* The 0x8f /0 variant of this instruction doesn't get its /r value verified. */
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync return false;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync /* The 0xc6 /0 and 0xc7 /0 variants of this instruction don't get their /r values verified. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return false;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return true;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync * Callback for reading bytes.
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync * @todo This should check that the disassembler doesn't do unnecessary reads,
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync * however the current doesn't do this and is just complicated...
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic DECLCALLBACK(int) MyDisasInstrRead(PDISCPUSTATE pDisState, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Straight forward reading.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Jumping up the stream.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * This occurs when the byte sequence is added to the output string.
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync /* reset the stream. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* skip ahead. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* do the reading. */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync RTStrmPrintf(g_pStdErr, "Reading before current instruction!\n");
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Disassembles a block of memory.
dccbbd8ec5b45b567312112e7edd5c7130d56262vboxsync * @returns VBox status code.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param argv0 Program name (for errors and warnings).
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param enmCpuMode The cpu mode to disassemble in.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param uAddress The address we're starting to disassemble at.
41738f3838049e665b571d59d971cc5c74efb6dcvboxsync * @param uHighlightAddr The address of the instruction that should be
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * highlighted. Pass UINT64_MAX to keep quiet.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param pbFile Where to start disassemble.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param cbFile How much to disassemble.
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync * @param enmStyle The assembly output style.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param fListing Whether to print in a listing like mode.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param enmUndefOp How to deal with undefined opcodes.
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsyncstatic int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress,
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync uint64_t uHighlightAddr, uint8_t *pbFile, size_t cbFile,
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync ASMSTYLE enmStyle, bool fListing, UNDEFOPHANDLING enmUndefOp)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Initialize the CPU context.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync RTPrintf(" BITS %d\n", enmCpuMode == DISCPUMODE_16BIT ? 16 : enmCpuMode == DISCPUMODE_32BIT ? 32 : 64);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * The loop.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * Disassemble it.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync int rc = DISInstrToStrWithReader(State.uAddress, enmCpuMode, MyDisasInstrRead, &State,
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync &State.Cpu, &State.cbInstr, State.szLine, sizeof(State.szLine));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte)
RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
RTPrintf("%s: error at %#RX64: undefined opcode (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
return rcRet;
switch (ch)
bool fListing = true;
bool fHexBytes = false;
int ch;
RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
switch (ch)
fListing = true;
fListing = false;
RTStrmPrintf(g_pStdErr, "%s: unknown undefined opcode handling method: %s\n", argv0, ValueUnion.psz);
fHexBytes = true;
if (fHexBytes)
char ch2;
while (*psz)
/** @todo this stuff belongs in IPRT, same stuff as mac address reading. Could be reused for IPv6 with a different item size.*/
psz++;
if (!ch2)
if (!pb)
rc = MyDisasmBlock(argv0, enmCpuMode, uAddress, uHighlightAddr, pb, cb, enmStyle, fListing, enmUndefOp);
void *pvFile;
rc = MyDisasmBlock(argv0, enmCpuMode, uAddress, uHighlightAddr, (uint8_t *)pvFile, cbFile, enmStyle, fListing, enmUndefOp);