text: //----------------------------------------------------------------------------
  //
  // Disassembly portions of X86 machine implementation.
  //
  // Copyright (C) Microsoft Corporation, 2000-2002.
  //
  //----------------------------------------------------------------------------
  
  #include "ntsdp.hpp"
  
  #include "i386_dis.h"
  
  UCHAR g_X86Int3[] = { 0xcc };
  
  //----------------------------------------------------------------------------
  //
  // BaseX86MachineInfo methods.
  //
  //----------------------------------------------------------------------------
  
  /*****                     macros and defines                          *****/
  
  #define X86_CS_OVR 0x2e
  
  #define BIT20(b) ((b) & 0x07)
  #define BIT53(b) (((b) >> 3) & 0x07)
  #define BIT76(b) (((b) >> 6) & 0x03)
  #define MAXOPLEN 10
  
  /*****                     static tables and variables                 *****/
  
  char* g_X86Reg8[] =
  {
      "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
      "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
  };
  char* g_Amd64ExtendedReg8[] =
  {
      "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"
  };
  char* g_X86RegBase[] =
  {
      "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
      "8", "9", "10", "11", "12", "13", "14", "15"
  };
  char *g_X86Mrm16[] =
  {
      "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx",
      "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
  };
  char *g_X86Mrm32[] =
  {
      "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
      "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
  };
  char *g_X86Mrm64[] =
  {
      "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
  };
  
  UCHAR g_X86Reg16Idx[] =
  {
      X86_NBX, X86_NBX, X86_NBP, X86_NBP,
      X86_NSI, X86_NDI, X86_NBP, X86_NBX,
  };
  UCHAR g_X86Reg16Idx2[] =
  {
      X86_NSI, X86_NDI, X86_NSI, X86_NDI
  };
  UCHAR g_X86RegIdx[] =
  {
      X86_NAX, X86_NCX, X86_NDX, X86_NBX,
      X86_NSP, X86_NBP, X86_NSI, X86_NDI,
      AMD64_R8, AMD64_R9, AMD64_R10, AMD64_R11,
      AMD64_R12, AMD64_R13, AMD64_R14, AMD64_R15
  };
  
  static char sregtab[] = "ecsdfg";  // first letter of ES, CS, SS, DS, FS, GS
  
  char* g_CompareIb[] = { "eq", "lt", "le", "unord", "ne", "nlt", "nle", "ord" };
  
  char    hexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7',
                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  
  static int              g_MrmMod;       /* mod of mod/rm byte */
  static int              g_MrmRm;        /* rm of mod/rm byte */
  static int              g_MrmArg;       /* return reg value (of mod/rm) */
  static unsigned char    *g_InstrMem;    /* current position in instruction */
  
  ADDR                    EAaddr[2];      //  offset of effective address
  static int              EAsize[2];      //  size of effective address item
  static char             *g_EaSegNames[2];   //  normal segment for operand
  
  #define IPREL_MARKER "<-IPREL->"
  
  BOOL g_X86ModrmHasIpRelOffset;
  LONG g_X86IpRelOffset;
  
  int g_SegAddrMode;      /* global address size in bits */
  int g_SegOpSize;        /* global operand size in bits */
  int g_AddrMode;         /* local address size in bits */
  int g_OpSize;           /* operand size in bits */
  
  int g_ExtendOpCode;
  int g_ExtendAny;
  int g_ExtendMrmReg;
  int g_ExtendSibIndex;
  int g_ExtendRm;
  
  BOOL g_MovX;            // Indicates a MOVSX or MOVZX.
  BOOL g_MovSXD;
  BOOL g_ForceMrmReg32;   // M/RM register is always 32-bit.
  BOOL g_MmRegEa;         // Use mm? registers in reg-only EA.
  BOOL g_XmmRegEa;        // Use xmm? registers in reg-only EA.
  BOOL g_ControlFlow;     // Control flow instruction.
  
  int  g_RepPrefix;
  
  enum
  {
      XMM_SS,
      XMM_SD,
      XMM_PS,
      XMM_PD,
  };
  
  int                     g_XmmOpSize;
  
  enum
  {
      JCC_EA_NONE,
      // Branch must be no-branch + 1.
      JCC_EA_NO_BRANCH,
      JCC_EA_BRANCH,
  };
  
  // First entry are bits that must be zero, second
  // and third entries are bit shifts for bits that must match.
  ULONG g_JccCheckTable[][3] =
  {
      X86_BIT_FLAGOF, 0, 0,                               // JNO
      X86_BIT_FLAGCF, 0, 0,                               // JNB
      X86_BIT_FLAGZF, 0, 0,                               // JNZ
      X86_BIT_FLAGCF | X86_BIT_FLAGZF, 0, 0,              // JNBE
      X86_BIT_FLAGSF, 0, 0,                               // JNS
      X86_BIT_FLAGPF, 0, 0,                               // JNP
      0, 7, 11,                                           // JNL
      X86_BIT_FLAGZF, 7, 11,                              // JNLE
  };
  
  //      internal function definitions
  
  void OutputHexString(char **, PUCHAR, int);
  void OutputHexValue(char **, PUCHAR, int, int);
  void OutputExHexValue(char **, PUCHAR, int, int);
  void OutputHexCode(char **, PUCHAR, int);
  void X86OutputString(char **, char *);
  
  void OutputHexAddr(PSTR *, PADDR);
  
  #define FormSelAddress(Addr, Sel, Off) \
      FormAddr(Sel, Off, 0, Addr)
  #define FormSegRegAddress(Addr, SegReg, Off) \
      FormAddr(SegReg, Off, FORM_SEGREG, Addr)
  
  void
  GetSegAddrOpSizes(MachineInfo* Machine, PADDR Addr)
  {
      if ((Type(*Addr) & ADDR_1664) ||
          ((Type(*Addr) & ADDR_FLAT) &&
           Machine->m_ExecTypes[0] == IMAGE_FILE_MACHINE_AMD64))
      {
          g_SegAddrMode = 64;
          // X86-64 defaults to 32-bit operand sizes even in 64-bit code.
          // Only the address size changes.  An operand size prefix
          // switches from 32- to 64-bit.
          g_SegOpSize = 32;
      }
      else if (Type(*Addr) & (ADDR_V86 | ADDR_16))
      {
          g_SegAddrMode = 16;
          g_SegOpSize = 16;
      }
      else
      {
          g_SegAddrMode = 32;
          g_SegOpSize = 32;
      }
  
      g_AddrMode = g_SegAddrMode;
      g_OpSize = g_SegOpSize;
  }
  
  void
  OverrideAddrMode(void)
  {
      switch(g_SegAddrMode)
      {
      case 16:
          g_AddrMode = 32;
          break;
      case 32:
          g_AddrMode = 16;
          break;
      case 64:
          g_AddrMode = 32;
          break;
      default:
          DBG_ASSERT(FALSE);
          break;
      }
  }
  
  void
  OverrideOpSize(int OverrideOp)
  {
      switch(g_SegAddrMode)
      {
      case 16:
          g_OpSize = 32;
          break;
      case 32:
          g_OpSize = 16;
          break;
      case 64:
          // X86-64 defaults to 32-bit operand sizes even in 64-bit code.
          // Only the address size changes.  A REX operand size prefix
          // switches from 32- to 64-bit.
          if (OverrideOp == 0x66)
          {
              g_OpSize = 16;
          }
          else if (OverrideOp & 8)
          {
              g_OpSize = 64;
          }
          break;
      default:
          DBG_ASSERT(FALSE);
          break;
      }
  }
  
  void
  ExtendOps(int opcode)
  {
      // x86-64 uses these opcodes as the REX override.
      OverrideOpSize(opcode);
  
      g_ExtendOpCode = opcode;
      g_ExtendAny = 8;
      if (opcode & 1)
      {
          g_ExtendRm = 8;
      }
      if (opcode & 2)
      {
          g_ExtendSibIndex = 8;
      }
      if (opcode & 4)
      {
          g_ExtendMrmReg = 8;
      }
  }
  
  void
  IgnoreExtend(BOOL Verbose)
  {
      //
      // Resets any extensions that may have happened.
      // The REX prefix must be the last
      // prefix of an instruction and is ignored otherwise,
      // so this reset is done when any prefix is encountered
      // after the REX prefix.  This should normally never
      // happen but technically it's valid code so we should handle it.
      //
  
      if (g_ExtendOpCode)
      {
          if (Verbose)
          {
              WarnOut("REX prefix ignored\n");
          }
  
          if (g_ExtendOpCode & 8)
          {
              // Op size was changed so put it back.  This
              // is tricky since in theory an op size override
              // prefix could also be present, but let's not
              // worry about that for now.
              g_OpSize = g_SegOpSize;
          }
  
          g_ExtendOpCode = 0;
          g_ExtendAny = 0;
          g_ExtendRm = 0;
          g_ExtendSibIndex = 0;
          g_ExtendMrmReg = 0;
      }
  }
  
  struct AMD_3DNOW_OPSTR
  {
      PSTR Str;
      UCHAR Opcode;
  };
  
  AMD_3DNOW_OPSTR g_Amd3DNowOpStr[] =
  {
      "pavgusb", 0xBF,
      "pfadd", 0x9E,
      "pfsub", 0x9A,
      "pfsubr", 0xAA,
      "pfacc", 0xAE,
      "pfcmpge", 0x90,
      "pfcmpgt", 0xA0,
      "pfcmpeq", 0xB0,
      "pfmin", 0x94,
      "pfmax", 0xA4,
      "pi2fd", 0x0D,
      "pf2id", 0x1D,
      "pfrcp", 0x96,
      "pfrsqrt", 0x97,
      "pfmul", 0xB4,
      "pfrcpit1", 0xA6,
      "pfrsqit1", 0xA7,
      "pfrcpit2", 0xB6,
      "pmulhrw", 0xB7,
      "pf2iw", 0x1C,
      "pfnacc", 0x8A,
      "pfpnacc", 0x8E,
      "pi2fw", 0x0C,
      "pswapd", 0xBB,
  };
  
  PSTR
  GetAmd3DNowOpString(UCHAR Opcode)
  {
      UCHAR i;
  
      for (i = 0; i < sizeof(g_Amd3DNowOpStr) / sizeof(g_Amd3DNowOpStr[0]); i++)
      {
          if (g_Amd3DNowOpStr[i].Opcode == Opcode)
          {
              return g_Amd3DNowOpStr[i].Str;
          }
      }
  
      return NULL;
  }
  
  BOOL
  BaseX86MachineInfo::Disassemble(ProcessInfo* Process,
                                  PADDR paddr, PSTR pchDst, BOOL fEAout)
  {
      ULONG64 Offset = Off(*paddr);
      int     opcode;                     /* current opcode */
      int     olen = 2;                   /* operand length */
      int     alen = 2;                   /* address length */
      int     end = FALSE;                /* end of instruction flag */
      int     mrm = FALSE;                /* indicator that modrm is generated*/
      unsigned char *action;              /* action for operand interpretation*/
      int     indx;                       /* temporary index */
      int     action2;                    /* secondary action */
      ULONG   instlen;                    /* instruction length */
      ULONG   cBytes;                     //  bytes read into instr buffer
      int     segOvr = 0;                 /* segment override opcode */
      UCHAR   membuf[X86_MAX_INSTRUCTION_LEN]; /* current instruction buffer */
      char    *pEAlabel = "";             //  optional label for operand
  
      char    *pchResultBuf = pchDst;     //  working copy of pchDst pointer
      char    RepPrefixBuffer[32];        //  rep prefix buffer
      char    *pchRepPrefixBuf = RepPrefixBuffer; //  pointer to prefix buffer
      char    OpcodeBuffer[16];           //  opcode buffer
      char    *pchOpcodeBuf = OpcodeBuffer;   //  pointer to opcode buffer
      char    OperandBuffer[MAX_SYMBOL_LEN + 20]; //  operand buffer
      char    *pchOperandBuf = OperandBuffer; //  pointer to operand buffer
      char    ModrmBuffer[MAX_SYMBOL_LEN + 20];   //  modRM buffer
      char    *pchModrmBuf = ModrmBuffer; //  pointer to modRM buffer
      char    EABuffer[128];              //  effective address buffer
      char    *pchEABuf = EABuffer;       //  pointer to EA buffer
  
      unsigned char BOPaction;
      int     subcode;                    /* bop subcode */
      int     JccEa;
      LONGLONG Branch;
  
      g_X86ModrmHasIpRelOffset = FALSE;
      g_MovX = FALSE;
      g_MovSXD = FALSE;
      g_ForceMrmReg32 = FALSE;
      g_MmRegEa = FALSE;
      g_XmmRegEa = FALSE;
      g_ControlFlow = FALSE;
      EAsize[0] = EAsize[1] = 0;          //  no effective address
      g_EaSegNames[0] = dszDS_;
      g_EaSegNames[1] = dszES_;
      g_RepPrefix = 0;
      g_XmmOpSize = XMM_PS;
      g_ExtendOpCode = 0;
      g_ExtendAny = 0;
      g_ExtendMrmReg = 0;
      g_ExtendSibIndex = 0;
      g_ExtendRm = 0;
      JccEa = JCC_EA_NONE;
  
      GetSegAddrOpSizes(this, paddr);
      alen = g_AddrMode / 8;
      olen = g_OpSize / 8;
  
      OutputHexAddr(&pchResultBuf, paddr);
  
      *pchResultBuf++ = ' ';
  
      if (fnotFlat(*paddr) ||
          m_Target->ReadVirtual(Process, Flat(*paddr),
                                membuf, X86_MAX_INSTRUCTION_LEN,
                                &cBytes) != S_OK)
      {
          ZeroMemory(membuf, X86_MAX_INSTRUCTION_LEN);
          cBytes = 0;
      }
  
      g_InstrMem = membuf;                /* point to begin of instruction */
      opcode = *g_InstrMem++;                   /* get opcode */
  
      if ( opcode == 0xc4 && *g_InstrMem == 0xC4 )
      {
          g_InstrMem++;
          X86OutputString(&pchOpcodeBuf,"BOP");
          action = &BOPaction;
          BOPaction = IB | END;
          subcode =  *g_InstrMem;
          if ( subcode == 0x50 || subcode == 0x52 || subcode == 0x53 ||
               subcode == 0x54 || subcode == 0x57 || subcode == 0x58 ||
               subcode == 0x58 )
          {
              BOPaction = IW | END;
          }
      }
      else
      {
          X86OutputString(&pchOpcodeBuf, distbl[opcode].instruct);
          action = actiontbl + distbl[opcode].opr; /* get operand action */
      }
  
  /*****          loop through all operand actions               *****/
  
      do
      {
          action2 = (*action) & 0xc0;
          switch((*action++) & 0x3f)
          {
          case ALT:                   /* alter the opcode if not 16-bit */
              if (g_OpSize > 16)
              {
                  indx = *action++;
                  pchOpcodeBuf = &OpcodeBuffer[indx];
                  if (indx == 0)
                  {
                      X86OutputString(&pchOpcodeBuf, g_OpSize == 32 ?
                                      dszCWDE : dszCDQE);
                  }
                  else if (g_OpSize == 64)
                  {
                      *pchOpcodeBuf++ = 'q';
                      if (indx == 1)
                      {
                          *pchOpcodeBuf++ = 'o';
                      }
                  }
                  else
                  {
                      *pchOpcodeBuf++ = 'd';
                      if (indx == 1)
                      {
                          *pchOpcodeBuf++ = 'q';
                      }
                  }
              }
              break;
  
          case XMMSD:                 /* SSE-style opcode rewriting */
              {
                  char ScalarOrPacked, SingleOrDouble;
                  char* DquOrQ, *DqOrQ, *SsdOrUpsd, *CvtPd, *CvtPs;
                  char* MovQD6, *Shuf;
                  char* Scan;
  
                  g_MmRegEa = TRUE;
                  DquOrQ = "q";
                  DqOrQ = "q";
                  SsdOrUpsd = "s?";
                  CvtPd = NULL;
                  CvtPs = NULL;
                  MovQD6 = NULL;
                  switch(g_RepPrefix)
                  {
                  case X86_REPN:
                      // Scalar double operation.
                      ScalarOrPacked = 's';
                      SingleOrDouble = 'd';
                      CvtPd = "pd2dq";
                      MovQD6 = "dq2q";
                      Shuf = "lw";
                      g_XmmOpSize = XMM_SD;
                      // Assume there was no other lock/rep/etc.
                      pchRepPrefixBuf = RepPrefixBuffer;
                      break;
                  case X86_REP:
                      // Scalar single operation.
                      ScalarOrPacked = 's';
                      SingleOrDouble = 's';
                      CvtPd = "dq2pd";
                      CvtPs = "tps2dq";
                      MovQD6 = "q2dq";
                      Shuf = "hw";
                      g_XmmOpSize = XMM_SS;
                      // Assume there was no other lock/rep/etc.
                      pchRepPrefixBuf = RepPrefixBuffer;
                      break;
                  default:
                      // No rep prefix means packed single or double
                      // depending on operand size.
                      ScalarOrPacked = 'p';
                      SsdOrUpsd = "up?";
                      if (g_OpSize == g_SegOpSize)
                      {
                          SingleOrDouble = 's';
                          CvtPs = "dq2ps";
                          Shuf = "w";
                          g_XmmOpSize = XMM_PS;
                      }
                      else
                      {
                          SingleOrDouble = 'd';
                          DqOrQ = "dq";
                          DquOrQ = "dqu";
                          CvtPd = "tpd2dq";
                          CvtPs = "ps2dq";
                          MovQD6 = "q";
                          Shuf = "d";
                          g_XmmRegEa = TRUE;
                          g_XmmOpSize = XMM_PD;
                      }
                      break;
                  }
  
                  pchOpcodeBuf = OpcodeBuffer;
                  while (*pchOpcodeBuf && *pchOpcodeBuf != ' ')
                  {
                      switch(*pchOpcodeBuf)
                      {
                      case ':':
                          *pchOpcodeBuf = ScalarOrPacked;
                          break;
                      case '?':
                          *pchOpcodeBuf = SingleOrDouble;
                          break;
                      case ',':
                          *pchOpcodeBuf = SingleOrDouble == 's' ? 'd' : 's';
                          break;
                      }
  
                      pchOpcodeBuf++;
                  }
  
                  switch(opcode)
                  {
                  case X86_MOVFREGMEM:
                  case X86_MOVFMEMREG:
                      // Append characters for MOVS[SD] and MOVUP[SD].
                      strcpy(pchOpcodeBuf, SsdOrUpsd);
                      if ((Scan = strchr(pchOpcodeBuf, '?')) != NULL)
                      {
                          *Scan = SingleOrDouble;
                      }
                      pchOpcodeBuf += strlen(pchOpcodeBuf);
                      break;
                  case X86_MOVNT:
                      // Append characters for MOVNTQ and MOVNTDQ.
                      X86OutputString(&pchOpcodeBuf, DqOrQ);
                      break;
                  case X86_MASKMOV:
                      // Append characters for MASKMOVQ and MASKMOVDQU.
                      X86OutputString(&pchOpcodeBuf, DquOrQ);
                      break;
                  case X86_CVTPD:
                      if (CvtPd == NULL)
                      {
                          // Invalid opcode.
                          pchOpcodeBuf = OpcodeBuffer;
                          X86OutputString(&pchOpcodeBuf, dszRESERVED);
                          action2 = END;
                      }
                      else
                      {
                          // Append characters for CVT<PD>.
                          X86OutputString(&pchOpcodeBuf, CvtPd);
                      }
                      break;
                  case X86_CVTPS:
                      if (CvtPs == NULL)
                      {
                          // Invalid opcode.
                          pchOpcodeBuf = OpcodeBuffer;
                          X86OutputString(&pchOpcodeBuf, dszRESERVED);
                          action2 = END;
                      }
                      else
                      {
                          // Append characters for CVT<PS>.
                          X86OutputString(&pchOpcodeBuf, CvtPs);
                      }
                      break;
                  case X86_MOVQ_D6:
                      if (MovQD6 == NULL)
                      {
                          // Invalid opcode.
                          pchOpcodeBuf = OpcodeBuffer;
                          X86OutputString(&pchOpcodeBuf, dszRESERVED);
                          action2 = END;
                      }
                      else
                      {
                          // Append characters for MOVQ D6 family.
                          X86OutputString(&pchOpcodeBuf, MovQD6);
                      }
                      break;
                  case X86_PSHUF:
                      // Append characters for PSHUF variants.
                      X86OutputString(&pchOpcodeBuf, Shuf);
                      break;
                  }
              }
              break;
  
          case AMD3DNOW:          /* AMD 3DNow post-instruction byte */
              {
                  PSTR OpStr;
  
                  // Get the trailing byte and look up
                  // the opcode string.
                  OpStr = GetAmd3DNowOpString(*g_InstrMem++);
                  if (OpStr == NULL)
                  {
                      // Not a defined 3DNow instruction.
                      // Leave the ??? in the opstring.
                      break;
                  }
  
                  // Update opstring to real text.
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, OpStr);
              }
              break;
  
          case STROP:
              //  compute size of operands in indx
              //  also if dword operands, change fifth
              //  opcode letter from 'w' to 'd'.
  
              if (opcode & 1)
              {
                  if (g_OpSize == 64)
                  {
                      indx = 8;
                      OpcodeBuffer[4] = 'q';
                  }
                  else if (g_OpSize == 32)
                  {
                      indx = 4;
                      OpcodeBuffer[4] = 'd';
                  }
                  else
                  {
                      indx = 2;
                  }
              }
              else
              {
                  indx = 1;
              }
  
              if (*action & 1)
              {
                  if (fEAout)
                  {
                      if (g_AddrMode > 16)
                      {
                          FormSelAddress(&EAaddr[0], 0, GetReg64(X86_NSI));
                      }
                      else
                      {
                          FormSegRegAddress(&EAaddr[0], SEGREG_DATA,
                                            GetReg16(X86_NSI));
                      }
                      EAsize[0] = indx;
                  }
              }
              if (*action++ & 2)
              {
                  if (fEAout)
                  {
                      if (g_AddrMode > 16)
                      {
                          FormSelAddress(&EAaddr[1], 0, GetReg64(X86_NDI));
                      }
                      else
                      {
                          FormSegRegAddress(&EAaddr[1], SEGREG_ES,
                                            GetReg16(X86_NDI));
                      }
                      EAsize[1] = indx;
                  }
              }
              break;
  
          case CHR:                   /* insert a character */
              *pchOperandBuf++ = *action++;
              break;
  
          case CREG:                  /* set debug, test or control reg */
              if (opcode & 0x04)
              {
                  *pchOperandBuf++ = 't';
              }
              else if (opcode & 0x01)
              {
                  *pchOperandBuf++ = 'd';
              }
              else
              {
                  *pchOperandBuf++ = 'c';
              }
              *pchOperandBuf++ = 'r';
              if (g_MrmArg >= 10)
              {
                  *pchOperandBuf++ = (char)('0' + g_MrmArg / 10);
                  g_MrmArg %= 10;
              }
              *pchOperandBuf++ = (char)('0' + g_MrmArg);
              break;
  
          case SREG2:                 /* segment register */
              g_MrmArg = BIT53(opcode);    //  set value to fall through
  
          case SREG3:                 /* segment register */
              *pchOperandBuf++ = sregtab[g_MrmArg];  // reg is part of modrm
              *pchOperandBuf++ = 's';
              break;
  
          case BRSTR:                 /* get index to register string */
              g_MrmArg = *action++;        /*    from action table */
              goto BREGlabel;
  
          case BOREG:                 /* byte register (in opcode) */
              g_MrmArg = BIT20(opcode);    /* register is part of opcode */
              goto BREGlabel;
  
          case ALSTR:
              g_MrmArg = 0;                /* point to AL register */
          BREGlabel:
          case BREG:                  /* general register */
              if (g_ExtendAny && g_MrmArg < 8)
              {
                  X86OutputString(&pchOperandBuf, g_Amd64ExtendedReg8[g_MrmArg]);
              }
              else
              {
                  X86OutputString(&pchOperandBuf, g_X86Reg8[g_MrmArg]);
              }
              break;
  
          case WRSTR:                 /* get index to register string */
              g_MrmArg = *action++;        /*    from action table */
              goto WREGlabel;
  
          case VOREG:                 /* register is part of opcode */
              if (m_ExecTypes[0] == IMAGE_FILE_MACHINE_AMD64 &&
                  opcode >= 0x40 && opcode <= 0x4f)
              {
                  // Get rid of the inc/dec text as this
                  // isn't really an inc/dec.
                  pchOpcodeBuf = OpcodeBuffer;
  
                  // Process the REX override.
                  ExtendOps(opcode);
                  olen = g_OpSize / 8;
                  action2 = 0;
                  goto getNxtByte;
              }
  
              g_MrmArg = BIT20(opcode) + g_ExtendRm;
              goto VREGlabel;
  
          case AXSTR:
              g_MrmArg = 0;                /* point to eAX register */
          VREGlabel:
          case VREG:                  /* general register */
              if ((g_SegAddrMode == 64 &&
                   opcode >= 0x50 && opcode <= 0x5f) ||
                  g_MrmArg >= 8)
              {
                  // Push/pops are always 64-bit in 64-bit segments.
                  *pchOperandBuf++ = 'r';
              }
              else if (g_OpSize == 32 ||
                       opcode == X86_PEXTRW ||
                       opcode == X86_PMOVMSKB)
              {
                  *pchOperandBuf++ = 'e';
              }
              else if (g_OpSize == 64)
              {
                  *pchOperandBuf++ = 'r';
              }
          WREGlabel:
          case WREG:                  /* register is word size */
              X86OutputString(&pchOperandBuf, g_X86RegBase[g_MrmArg]);
              if (g_MrmArg >= 8)
              {
                  if (g_OpSize == 32)
                  {
                      *pchOperandBuf++ = 'd';
                  }
                  else if (g_OpSize == 16)
                  {
                      *pchOperandBuf++ = 'w';
                  }
              }
              break;
  
          case MMORWREG:
              if (g_XmmOpSize == XMM_SS || g_XmmOpSize == XMM_SD)
              {
                  goto VREGlabel;
              }
              // Fall through.
          MMWREGlabel:
          case MMWREG:
              if ((g_OpSize != g_SegOpSize &&
                   opcode != X86_CVTSPSD2SPI) ||
                  (g_RepPrefix == X86_REP &&
                   (opcode == X86_MOVDQAU_MR || opcode == X86_MOVDQAU_RM)))
              {
                  *pchOperandBuf++ = 'x';
              }
              *pchOperandBuf++ = 'm';
              *pchOperandBuf++ = 'm';
              if (g_MrmArg >= 10)
              {
                  *pchOperandBuf++ = (char)('0' + g_MrmArg / 10);
                  g_MrmArg %= 10;
              }
              *pchOperandBuf++ = g_MrmArg + '0';
              break;
  
          case XORMMREG:
              if (g_OpSize == g_SegOpSize)
              {
                  goto MMWREGlabel;
              }
              // Fall through.
          case XMMWREG:
              if (opcode != X86_PSHUF || g_XmmOpSize != XMM_PS)
              {
                  *pchOperandBuf++ = 'x';
              }
              *pchOperandBuf++ = 'm';
              *pchOperandBuf++ = 'm';
              if (g_MrmArg >= 10)
              {
                  *pchOperandBuf++ = (char)('0' + g_MrmArg / 10);
                  g_MrmArg %= 10;
              }
              *pchOperandBuf++ = g_MrmArg + '0';
              break;
  
          case IST_ST:
              X86OutputString(&pchOperandBuf, "st(0),st");
              *(pchOperandBuf - 5) += (char)g_MrmRm;
              break;
  
          case ST_IST:
              X86OutputString(&pchOperandBuf, "st,");
          case IST:
              X86OutputString(&pchOperandBuf, "st(0)");
              *(pchOperandBuf - 2) += (char)g_MrmRm;
              break;
  
          case xBYTE:                 /* set instruction to byte only */
              EAsize[0] = 1;
              pEAlabel = "byte ptr ";
              break;
  
          case VAR:
              if ((g_SegAddrMode == 64 || g_ExtendAny > 0) &&
                  opcode == 0x63)
              {
                  // In AMD64 REX32 and 64-bit modes this instruction
                  // is MOVSXD r64, r/m32 instead of ARPL r/m, reg.
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszMOVSXD);
                  action = &actiontbl[O_Reg_Modrm] + 1;
                  g_OpSize = 64;
                  g_MovSXD = TRUE;
                  goto DWORDlabel;
              }
              else if (opcode == 0xff)
              {
                  UCHAR Extra = BIT53(*g_InstrMem);
                  if (Extra >= 2 && Extra <= 5)
                  {
                      g_ControlFlow = TRUE;
  
                      // On x86-64 control-flow operations default to
                      // 64-bit opsize.
                      if (g_SegAddrMode == 64)
                      {
                          if (g_OpSize == 32)
                          {
                              g_OpSize = 64;
                          }
                      }
                  }
                  else if (g_SegAddrMode == 64 && Extra == 6)
                  {
                      // Push/pops are always 64-bit in 64-bit segments.
                      g_OpSize = 64;
                  }
              }
              else if (g_SegAddrMode == 64 && opcode == 0x8f)
              {
                  // Push/pops are always 64-bit in 64-bit segments.
                  g_OpSize = 64;
              }
              olen = g_OpSize / 8;
  
              if (g_OpSize == 64)
              {
                  goto QWORDlabel;
              }
              else if (g_OpSize == 32)
              {
                  goto DWORDlabel;
              }
  
          case xWORD:
              if (opcode == X86_PINSRW)
              {
                  g_ForceMrmReg32 = TRUE;
              }
              EAsize[0] = 2;
              pEAlabel = "word ptr ";
              break;
  
          case EDWORD:
              // Control register opsize is mode-independent.
              g_OpSize = g_SegAddrMode;
              if (g_OpSize == 64)
              {
                  goto QWORDlabel;
              }
          case xDWORD:
              if (opcode == X86_MOVDQ_7E && g_RepPrefix == X86_REP)
              {
                  // Switch to MOVQ xmm1, xmm2/m64.
                  pchRepPrefixBuf = RepPrefixBuffer;
                  *(pchOpcodeBuf - 1) = 'q';
                  EAsize[0] = 8;
                  pEAlabel = "qword ptr ";
                  g_XmmRegEa = TRUE;
                  action = &actiontbl[O_Sd_XmmReg_qModrm] + 2;
                  break;
              }
              // Fall through.
          DWORDlabel:
              EAsize[0] = 4;
              pEAlabel = "dword ptr ";
              break;
  
          case XMMOWORD:
              if (opcode == X86_PSHUF)
              {
                  if (g_XmmOpSize == XMM_PS)
                  {
                      g_MmRegEa = TRUE;
                      goto QWORDlabel;
                  }
                  else
                  {
                      EAsize[0] = 16;
                      pEAlabel = "oword ptr ";
                      break;
                  }
              }
  
              g_XmmRegEa = TRUE;
              if (opcode == X86_CVTPD)
              {
                  if (g_XmmOpSize == XMM_SS)
                  {
                      EAsize[0] = 8;
                      pEAlabel = "qword ptr ";
                  }
                  else
                  {
                      EAsize[0] = 16;
                      pEAlabel = "oword ptr ";
                  }
                  break;
              }
              else if (opcode == X86_CVTPS)
              {
                  EAsize[0] = 16;
                  pEAlabel = "oword ptr ";
                  break;
              }
              else if (opcode == X86_MOVQ_D6)
              {
                  if (g_XmmOpSize == XMM_SD)
                  {
                      // Switch to MOVDQ2Q mm, xmm.
                      EAsize[0] = 16;
                      pEAlabel = "oword ptr ";
                      action = &actiontbl[O_MmReg_qModrm] + 1;
                      break;
                  }
              }
              else if (opcode == X86_MOVHLPS && g_XmmOpSize == XMM_PS &&
                       BIT76(*g_InstrMem) == 3)
              {
                  // reg-reg form of MOVLPS is called MOVHLPS.
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszMOVHLPS);
              }
              else if (opcode == X86_MOVLHPS && g_XmmOpSize == XMM_PS &&
                       BIT76(*g_InstrMem) == 3)
              {
                  // reg-reg form of MOVHPS is called MOVLHPS.
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszMOVLHPS);
              }
  
              // Fall through.
  
          OWORDlabel:
          case OWORD:
              switch(g_XmmOpSize)
              {
              case XMM_SS:
                  EAsize[0] = 4;
                  pEAlabel = "dword ptr ";
                  if (opcode == X86_MOVQ_D6)
                  {
                      // Switch to MOVQ xmm1, xmm2/m64.
                      g_XmmRegEa = FALSE;
                      action = &actiontbl[O_Sd_XmmReg_qModrm] + 1;
                  }
                  break;
              case XMM_SD:
                  EAsize[0] = 8;
                  pEAlabel = "qword ptr ";
                  break;
              default:
                  if (opcode == 0x112 || opcode == 0x113 ||
                      opcode == 0x116 || opcode == 0x117 ||
                      opcode == X86_MOVQ_D6 ||
                      (g_OpSize == g_SegOpSize &&
                       (opcode == 0x12c || opcode == X86_CVTSPSD2SPI ||
                        opcode == X86_CVTSPSD2SPSD)))
                  {
                      EAsize[0] = 8;
                      pEAlabel = "qword ptr ";
                  }
                  else
                  {
                      EAsize[0] = 16;
                      pEAlabel = "oword ptr ";
                  }
                  break;
              }
              break;
  
          case XMMXWORD:
              g_XmmRegEa = TRUE;
              if (g_OpSize == g_SegOpSize)
              {
                  if (opcode == X86_MOVNT)
                  {
                      EAsize[0] = 8;
                      pEAlabel = "qword ptr ";
                  }
                  else
                  {
                      EAsize[0] = 4;
                      pEAlabel = "dword ptr ";
                  }
              }
              else
              {
                  if (opcode == X86_MOVNT)
                  {
                      EAsize[0] = 16;
                      pEAlabel = "oword ptr ";
                  }
                  else
                  {
                      EAsize[0] = 8;
                      pEAlabel = "qword ptr ";
                  }
              }
              break;
  
          case MMQWORD:
              // The REX prefix is ignored in front of most
              // FP and MM operations.  The only affect it
              // has is to allow extended register selection.
              // Reset the opsize as the 64-bit opsize behavior
              // of the REX prefix is ignored.
              if (g_ExtendOpCode & 8)
              {
                  g_OpSize = g_SegOpSize;
              }
  
              if (g_OpSize != g_SegOpSize &&
                  (opcode == X86_MOVDQAU_MR || opcode == X86_MOVDQAU_RM))
              {
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszMOVDQA);
              }
              else if (g_RepPrefix == X86_REP &&
                       (opcode == X86_MOVDQAU_MR || opcode == X86_MOVDQAU_RM))
              {
                  pchRepPrefixBuf = RepPrefixBuffer;
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszMOVDQU);
                  g_XmmRegEa = TRUE;
                  goto OWORDlabel;
              }
  
              if (opcode == X86_CVTSPI2SPSD)
              {
                  g_XmmRegEa = FALSE;
                  if (g_XmmOpSize == XMM_SS || g_XmmOpSize == XMM_SD)
                  {
                      g_MmRegEa = FALSE;
                      goto DWORDlabel;
                  }
              }
              else if (g_OpSize != g_SegOpSize)
              {
                  g_XmmRegEa = TRUE;
                  goto OWORDlabel;
              }
              g_MmRegEa = TRUE;
          QWORDlabel:
          case QWORD:
              EAsize[0] = 8;
              pEAlabel = "qword ptr ";
              break;
  
          case TBYTE:
              EAsize[0] = 10;
              pEAlabel = "tbyte ptr ";
              break;
  
          case FARPTR:
              g_ControlFlow = TRUE;
  
              // On x86-64 control-flow operations default to
              // 64-bit opsize.
              if (g_SegAddrMode == 64)
              {
                  if (g_OpSize == 32)
                  {
                      g_OpSize = 64;
                  }
              }
  
              switch(g_OpSize)
              {
              case 16:
                  EAsize[0] = 4;
                  pEAlabel = "dword ptr ";
                  break;
              default:
                  EAsize[0] = 6;
                  pEAlabel = "fword ptr ";
                  break;
              }
              break;
  
          case LMODRM:                //  output modRM data type
              if (g_MrmMod != 3)
              {
                  X86OutputString(&pchOperandBuf, pEAlabel);
              }
              else
              {
                  EAsize[0] = 0;
              }
  
          case MODRM:                 /* output modrm string */
              if (segOvr)             /* in case of segment override */
              {
                  X86OutputString(&pchOperandBuf, distbl[segOvr].instruct);
              }
              *pchModrmBuf = '\0';
              X86OutputString(&pchOperandBuf, ModrmBuffer);
              break;
  
          case ADDRP:                 /* address pointer */
              // segment
              OutputHexString(&pchOperandBuf, g_InstrMem + olen, 2);
              *pchOperandBuf++ = ':';
              // offset
              OutputSymbol(&pchOperandBuf, g_InstrMem, olen, segOvr);
              g_InstrMem += olen + 2;
              break;
  
          case JCC8:
              JccEa = ComputeJccEa(opcode, fEAout);
              // Fall through.
          case REL8:                  /* relative address 8-bit */
              if (opcode == 0xe3 && g_AddrMode > 16)
              {
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, g_AddrMode == 64 ?
                                  dszJRCXZ : dszJECXZ);
              }
              Branch = *(char *)g_InstrMem++; /* get the 8-bit rel offset */
              goto DoRelDispl;
  
          case JCCX:
              JccEa = ComputeJccEa(opcode, fEAout);
              // Fall through.
          case REL16:                 /* relative address 16-/32-bit */
              switch(g_AddrMode)
              {
              case 16:
                  Branch = *(short UNALIGNED *)g_InstrMem;
                  g_InstrMem += 2;
                  break;
              default:
                  Branch = *(long UNALIGNED *)g_InstrMem;
                  g_InstrMem += 4;
                  break;
              }
          DoRelDispl:
              /* calculate address */
              Branch += Offset + (g_InstrMem - membuf);
              // rel8 and rel16 are only used in control-flow
              // instructions so the target is always relative
              // to CS.  Pass in the CS override to force this.
              OutputSymbol(&pchOperandBuf, (PUCHAR)&Branch, alen, X86_CS_OVR);
              break;
  
          case UBYTE:                 //  unsigned byte for int/in/out
              OutputHexString(&pchOperandBuf, g_InstrMem, 1);  //  ubyte
              g_InstrMem++;
              break;
  
          case CMPIB:
              // Immediate byte comparison encoding for CMP[SP][SD].
              if (*g_InstrMem < 8)
              {
                  X86OutputString(&pchOperandBuf, g_CompareIb[*g_InstrMem]);
                  g_InstrMem++;
              }
              else
              {
                  olen = 1;
                  goto DoImmed;
              }
              break;
  
          case IB:                    /* operand is immediate byte */
              // postop for AAD/AAM is 0x0a
              if ((opcode & ~1) == 0xd4)
              {
                  // test post-opcode byte
                  if (*g_InstrMem++ != 0x0a)
                  {
                      X86OutputString(&pchOperandBuf, dszRESERVED);
                  }
                  break;
              }
              olen = 1;               /* set operand length */
              goto DoImmed;
  
          case IW:                    /* operand is immediate word */
              olen = 2;               /* set operand length */
  
          case IV:                    /* operand is word or dword */
          DoImmed:
              // AMD64 immediates are only 64-bit in the case of
              // mov reg, immed.  All other operations involving
              // immediates stay 32-bit.
              if (olen == 8 &&
                  (opcode < 0xb8 || opcode > 0xbf))
              {
                  olen = 4;
              }
              OutputHexValue(&pchOperandBuf, g_InstrMem, olen, FALSE);
              g_InstrMem += olen;
              break;
  
          case XB:
              OutputExHexValue(&pchOperandBuf, g_InstrMem, 1, g_OpSize / 8);
              g_InstrMem++;
              break;
  
          case OFFS:                  /* operand is offset */
              EAsize[0] = (opcode & 1) ? olen : 1;
  
              if (segOvr)             /* in case of segment override */
              {
                  X86OutputString(&pchOperandBuf, distbl[segOvr].instruct);
              }
  
              *pchOperandBuf++ = '[';
              //  offset
              OutputSymbol(&pchOperandBuf, g_InstrMem, alen, segOvr);
              g_InstrMem += alen;
              *pchOperandBuf++ = ']';
              break;
  
          case X86_GROUP:             /* operand is of group 1,2,4,6 or 8 */
              /* output opcode symbol */
              X86OutputString(&pchOpcodeBuf, group[*action++][g_MrmArg]);
              break;
  
          case GROUPT:                /* operand is of group 3,5 or 7 */
              indx = *action;         /* get indx into group from action */
              goto doGroupT;
  
          case EGROUPT:               /* x87 ESC (D8-DF) group index */
              indx = BIT20(opcode) * 2; /* get group index from opcode */
              /* some operand variations exist */
              if (g_MrmMod == 3)
              {
                  /* for x87 and mod == 3 */
                  ++indx;             /* take the next group table entry */
                  if (indx == 3)
                  {
                      /* for x87 ESC==D9 and mod==3 */
                      if (g_MrmArg > 3)
                      {
                          /* for those D9 instructions */
                          indx = 12 + g_MrmArg; /* offset index to table by 12 */
                          g_MrmArg = g_MrmRm;   /* set secondary index to rm */
                      }
                  }
                  else if (indx == 7)
                  {
                      /* for x87 ESC==DB and mod==3 */
                      if (g_MrmArg == 4)
                      {
                          /* if g_MrmArg==4 */
                          g_MrmArg = g_MrmRm;     /* set secondary group table index */
                      }
                      else if ((g_MrmArg < 4) || (g_MrmArg > 4 && g_MrmArg < 7))
                      {
                          // adjust for pentium pro opcodes
                          indx = 24;   /* offset index to table by 24*/
                      }
                  }
              }
          doGroupT:
              /* handle group with different types of operands */
  
              X86OutputString(&pchOpcodeBuf, groupt[indx][g_MrmArg].instruct);
              action = actiontbl + groupt[indx][g_MrmArg].opr;
              /* get new action */
              break;
  
          case OPC0F:              /* secondary opcode table (opcode 0F) */
              opcode = *g_InstrMem++;    /* get real opcode */
              g_MovX = (BOOL)(opcode == 0xBF || opcode == 0xB7);
              // Point opcode into secondary opcode portion of table.
              opcode += 256;
              goto getNxtByte1;
  
          case ADR_OVR:               /* address override */
              IgnoreExtend(TRUE);
              olen = g_OpSize / 8;
              OverrideAddrMode();
              alen = g_AddrMode / 8;
              goto getNxtByte;
  
          case OPR_OVR:               /* operand size override */
              IgnoreExtend(TRUE);
              OverrideOpSize(opcode);
              olen = g_OpSize / 8;
              goto getNxtByte;
  
          case SEG_OVR:               /* handle segment override */
              IgnoreExtend(TRUE);
              olen = g_OpSize / 8;
              segOvr = opcode;        /* save segment override opcode */
              pchOpcodeBuf = OpcodeBuffer;  // restart the opcode string
              goto getNxtByte;
  
          case REP:                   /* handle rep/lock prefixes */
              IgnoreExtend(TRUE);
              olen = g_OpSize / 8;
              g_RepPrefix = opcode;
              *pchOpcodeBuf = '\0';
              if (pchRepPrefixBuf != RepPrefixBuffer)
              {
                  *pchRepPrefixBuf++ = ' ';
              }
              X86OutputString(&pchRepPrefixBuf, OpcodeBuffer);
              pchOpcodeBuf = OpcodeBuffer;
          getNxtByte:
              opcode = *g_InstrMem++;        /* next byte is opcode */
          getNxtByte1:
              action = actiontbl + distbl[opcode].opr;
              X86OutputString(&pchOpcodeBuf, distbl[opcode].instruct);
              break;
  
          case NOP:
              if (opcode == X86_PAUSE && g_RepPrefix == X86_REP)
              {
                  pchRepPrefixBuf = RepPrefixBuffer;
                  pchOpcodeBuf = OpcodeBuffer;
                  X86OutputString(&pchOpcodeBuf, dszPAUSE);
              }
              // Fall through.
          default:                    /* opcode has no operand */
              break;
          }
  
          /* secondary action */
          switch (action2)
          {
          case MRM:
              /* generate modrm for later use */
              /* ignore if it has been generated */
              if (!mrm)
              {
                  /* generate modrm */
                  DIdoModrm(Process, &pchModrmBuf, segOvr, fEAout);
                  mrm = TRUE;         /* remember its generation */
              }
              break;
  
          case COM:                   /* insert a comma after operand */
              *pchOperandBuf++ = ',';
              break;
  
          case END:                   /* end of instruction */
              end = TRUE;
              break;
          }
      } while (!end);                        /* loop til end of instruction */
  
  /*****       prepare disassembled instruction for output              *****/
  
  //    dprintf("EAaddr[] = %08lx\n", (ULONG)Flat(EAaddr[0]));
  
  
      instlen = (ULONG)(g_InstrMem - membuf);
  
      if (instlen < cBytes)
      {
          cBytes = instlen;
      }
  
      int obOpcode = m_Ptr64 ? 35 : 26;
      int obOpcodeMin;
      int obOpcodeMax;
  
      int obOperand = m_Ptr64 ? 43 : 34;
      int obOperandMin;
      int obOperandMax;
  
      int cbOpcode;
      int cbOperand;
      int cbOffset;
      int cbEAddr;
  
      int obLineEnd = g_OutputWidth - 3;
  
      if (g_AsmOptions & DEBUG_ASMOPT_IGNORE_OUTPUT_WIDTH)
      {
          // Extend the line end out a long way but
          // not so much that overflows may occur.
          obLineEnd = 0x7fffff;
      }
  
      if (!(g_AsmOptions & DEBUG_ASMOPT_NO_CODE_BYTES))
      {
          OutputHexCode(&pchResultBuf, membuf, cBytes);
      }
      else
      {
          obOpcode -= 16;
          obOperand -= 16;
      }
  
      if (instlen > cBytes)
      {
          *pchResultBuf++ = '?';
          *pchResultBuf++ = '?';
          //  point past unread byte
          AddrAdd(paddr, 1);
          do
          {
              *pchResultBuf++ = ' ';
          } while (pchResultBuf < pchDst + obOpcode);
          X86OutputString(&pchResultBuf, "???\n");
          *pchResultBuf++ = '\0';
          return FALSE;
      }
  
      AddrAdd(paddr, instlen);
  
      PSTR Mark;
  
      // Now that we know the complete size of the instruction
      // we can correctly compute IP-relative absolute addresses.
      *pchOperandBuf = 0;
      if (g_X86ModrmHasIpRelOffset &&
          (Mark = strstr(OperandBuffer, IPREL_MARKER)) != NULL)
      {
          PSTR TailFrom, TailTo;
          ULONG64 IpRelAddr;
          size_t TailLen;
  
          // Move the tail of the string to the end of the buffer
          // to make space.
          TailFrom = Mark + sizeof(IPREL_MARKER) - 1;
          TailLen = pchOperandBuf - TailFrom;
          TailTo = OperandBuffer + (sizeof(OperandBuffer) - 1 - TailLen);
          memmove(TailTo, TailFrom, TailLen);
  
          // Compute the absolute address from the new IP
          // and the offset and format it into the buffer.
          IpRelAddr = Flat(*paddr) + g_X86IpRelOffset;
          OutputSymbol(&Mark, (PUCHAR)&IpRelAddr, g_SegAddrMode == 64 ? 8 : 4,
                       X86_CS_OVR);
          if (Mark < TailTo)
          {
              memmove(Mark, TailTo, TailLen);
              pchOperandBuf = Mark + TailLen;
          }
          else if (Mark >= TailTo + TailLen)
          {
              pchOperandBuf = Mark;
          }
          else
          {
              pchOperandBuf = Mark + (TailLen - (Mark - TailTo));
          }
      }
  
      //  if fEAout is set, build each EA with trailing space in EABuf
      //  point back over final trailing space if buffer nonnull
  
      if (fEAout)
      {
          for (indx = 0; indx < 2; indx++)
          {
              if (EAsize[indx])
              {
                  X86OutputString(&pchEABuf, segOvr ? distbl[segOvr].instruct
                                                 : g_EaSegNames[indx]);
                  OutputHexAddr(&pchEABuf, &EAaddr[indx]);
                  *pchEABuf++ = '=';
                  if (fFlat(EAaddr[indx]) &&
                      m_Target->ReadAllVirtual(Process, Flat(EAaddr[indx]),
                                               membuf, EAsize[indx]) == S_OK)
                  {
                      OutputHexString(&pchEABuf, membuf, EAsize[indx]);
                  }
                  else
                  {
                      while (EAsize[indx]--)
                      {
                          *pchEABuf++ = '?';
                          *pchEABuf++ = '?';
                      }
                  }
                  *pchEABuf++ = ' ';
              }
          }
  
          if (pchEABuf != EABuffer)
          {
              pchEABuf--;
          }
  
          switch(JccEa)
          {
          case JCC_EA_NO_BRANCH:
              X86OutputString(&pchEABuf, "[br=0]");
              break;
          case JCC_EA_BRANCH:
              X86OutputString(&pchEABuf, "[br=1]");
              break;
          }
      }
  
      //  compute lengths of component strings.
      //  if the rep string is nonnull,
      //      add the opcode string length to the operand
      //      make the rep string the opcode string
  
      cbOffset = (int)(pchResultBuf - pchDst);
      cbOperand = (int)(pchOperandBuf - OperandBuffer);
      cbOpcode = (int)(pchOpcodeBuf - OpcodeBuffer);
      if (pchRepPrefixBuf != RepPrefixBuffer)
      {
          cbOperand += cbOpcode + (cbOperand != 0);
          cbOpcode = (int)(pchRepPrefixBuf - RepPrefixBuffer);
      }
      cbEAddr = (int)(pchEABuf - EABuffer);
  
      //  compute the minimum and maximum offset values for
      //      opcode and operand strings.
      //  if strings are nonnull, add extra for separating space
  
      obOpcodeMin = cbOffset + 1;
      obOperandMin = obOpcodeMin + cbOpcode + 1;
      obOperandMax = obLineEnd - cbEAddr - (cbEAddr != 0) - cbOperand;
      obOpcodeMax = obOperandMax - (cbOperand != 0) - cbOpcode;
  
      //  compute the opcode and operand offsets.  set offset as
      //      close to the default values as possible.
  
      if (obOpcodeMin > obOpcode)
      {
          obOpcode = obOpcodeMin;
      }
      else if (obOpcodeMax < obOpcode)
      {
          obOpcode = obOpcodeMax;
      }
  
      obOperandMin = obOpcode + cbOpcode + 1;
  
      if (obOperandMin > obOperand)
      {
          obOperand = obOperandMin;
      }
      else if (obOperandMax < obOperand)
      {
          obOperand = obOperandMax;
      }
  
      //  build the resultant string with the offsets computed
  
      //  output rep, opcode, and operand strings
  
      do
      {
          *pchResultBuf++ = ' ';
      } while (pchResultBuf < pchDst + obOpcode);
  
      if (pchRepPrefixBuf != RepPrefixBuffer)
      {
          *pchRepPrefixBuf = '\0';
          X86OutputString(&pchResultBuf, RepPrefixBuffer);
          do
          {
              *pchResultBuf++ = ' ';
          } while (pchResultBuf < pchDst + obOperand);
      }
  
      *pchOpcodeBuf = '\0';
      X86OutputString(&pchResultBuf, OpcodeBuffer);
  
      if (pchOperandBuf != OperandBuffer)
      {
          do
          {
              *pchResultBuf++ = ' ';
          } while (pchResultBuf < pchDst + obOperand);
          *pchOperandBuf = '\0';
          X86OutputString(&pchResultBuf, OperandBuffer);
      }
  
      //  append the EAddr string
  
      if (pchEABuf != EABuffer)
      {
          *pchEABuf = '\0';
          do
          {
              *pchResultBuf++ = ' ';
          } while (pchResultBuf < pchDst + obLineEnd - cbEAddr);
          X86OutputString(&pchResultBuf, EABuffer);
      }
  
      *pchResultBuf++ = '\n';
      *pchResultBuf = '\0';
      return TRUE;
  }
  
  void
  BaseX86MachineInfo::GetNextOffset(ProcessInfo* Process, BOOL StepOver,
                                    PADDR NextAddr, PULONG NextMachine)
  {
      ULONG   cBytes;
      UCHAR   membuf[X86_MAX_INSTRUCTION_LEN]; //  current instruction buffer
      UCHAR   *InstrMem;
      UCHAR   opcode;
      int     fPrefix = TRUE;
      int     fRepPrefix = FALSE;
      int     MrmMod;
      int     MrmArg;
      int     MrmRm;
      ULONG64 instroffset;
      int     subcode;
  
      // NextMachine is always the same.
      *NextMachine = m_ExecTypes[0];
  
      //  read instruction stream bytes into membuf and set mode and
      //      opcode size flags
  
      GetPC(NextAddr);
      instroffset = Flat(*NextAddr);
      GetSegAddrOpSizes(this, NextAddr);
  
      /* move full inst to local buffer */
      if (fnotFlat(*NextAddr) ||
          m_Target->ReadVirtual(Process, Flat(*NextAddr),
                                membuf, X86_MAX_INSTRUCTION_LEN,
                                &cBytes) != S_OK)
      {
          cBytes = 0;
      }
  
      // Ensure that membuf is padded with innocuous bytes in
      // the section that wasn't read.
      if (cBytes < X86_MAX_INSTRUCTION_LEN)
      {
          memset(membuf + cBytes, 0xcc, X86_MAX_INSTRUCTION_LEN - cBytes);
      }
  
      /* point to begin of instruction */
      InstrMem = membuf;
  
      //  read and process any prefixes first
  
      do
      {
          opcode = *InstrMem++;        /* get opcode */
          if (opcode == 0x66)
          {
              OverrideOpSize(opcode);
          }
          else if (m_ExecTypes[0] == IMAGE_FILE_MACHINE_AMD64 &&
                   opcode >= 0x40 && opcode <= 0x4f)
          {
              ExtendOps(opcode);
          }
          else if (opcode == 0x67)
          {
              OverrideAddrMode();
          }
          else if ((opcode & ~1) == 0xf2)
          {
              fRepPrefix = TRUE;
          }
          else if (opcode != 0xf0 && (opcode & ~0x18) != 0x26 &&
                   (opcode & ~1) != 0x64)
          {
              fPrefix = FALSE;
          }
      } while (fPrefix);
  
      //  for instructions that alter the TF (trace flag), return the
      //      offset of the next instruction despite the flag of StepOver
  
      if (((opcode & ~0x3) == 0x9c) && !g_WatchTrace)
      {
          //  9c-9f, pushf, popf, sahf, lahf
          ;
      }
      else if (opcode == 0xcf)
      {
          ULONG64 RetAddr[2];
          ADDR Sp;
          ULONG Seg;
  
          //  cf - iret - get RA from stack
          FormSegRegAddress(&Sp, SEGREG_STACK, GetReg64(X86_NSP));
  
          if (fnotFlat(Sp) ||
              m_Target->ReadAllVirtual(Process, Flat(Sp),
                                       RetAddr, g_SegAddrMode / 4) != S_OK)
          {
              instroffset = OFFSET_TRACE;
              goto Exit;
          }
  
          Seg = *(PUSHORT)((PUCHAR)RetAddr + g_SegAddrMode / 8);
          switch(g_SegAddrMode)
          {
          case 16:
              instroffset = EXTEND64(*(PUSHORT)RetAddr);
              break;
          case 32:
              instroffset = EXTEND64(*(PULONG)RetAddr);
              break;
          case 64:
              instroffset = RetAddr[0];
              break;
          }
  
          FormSelAddress(NextAddr, Seg, instroffset);
          ComputeFlatAddress(NextAddr, NULL);
          return;
      }
      else if (opcode == 0xc4 && *InstrMem == 0xc4)
      {
          subcode = *(InstrMem+1);
          if ( subcode == 0x50 ||
               subcode == 0x52 ||
               subcode == 0x53 ||
               subcode == 0x54 ||
               subcode == 0x57 ||
               subcode == 0x58 ||
               subcode == 0x5D )
          {
              InstrMem += 3;
          }
          else
          {
              InstrMem += 2;
          }
      }
      else if (!StepOver)
      {
          //  if tracing just return OFFSET_TRACE to trace
          instroffset = OFFSET_TRACE;
      }
      else if (opcode == 0xe8)
      {
          //  near direct jump
          InstrMem += g_OpSize > 16 ? 4 : 2;
      }
      else if (opcode == 0x9a)
      {
          //  far direct jump
          InstrMem += g_OpSize > 16 ? 6 : 4;
      }
      else if (opcode == 0xcd ||
               (opcode >= 0xe0 && opcode <= 0xe2))
      {
          //  loop / int nn instrs
          InstrMem++;
      }
      else if (opcode == 0xff)
      {
          //  indirect call - compute length
          opcode = *InstrMem++;               //  get modRM
          MrmArg = BIT53(opcode);
          if ((MrmArg & ~1) == 2)
          {
              MrmMod = BIT76(opcode);
              if (MrmMod != 3)
              {
                  //  nonregister operand
                  MrmRm = BIT20(opcode);
                  if (g_AddrMode > 16)
                  {
                      if (MrmRm == 4)
                      {
                          MrmRm = BIT20(*InstrMem++);    //  get base from SIB
                      }
                      if (MrmMod == 0)
                      {
                          if (MrmRm == 5)
                          {
                              InstrMem += 4;          //  long direct address
                          }                       //  else register
                      }
                      else if (MrmMod == 1)
                      {
                          InstrMem++;                 //  register with byte offset
                      }
                      else
                      {
                          InstrMem += 4;              //  register with long offset
                      }
                  }
                  else
                  {
                      // 16-bit mode
                      if (MrmMod == 0)
                      {
                          if (MrmRm == 6)
                          {
                              InstrMem += 2;          //  short direct address
                          }
                      }
                      else
                      {
                          InstrMem += MrmMod;            //  reg, byte, word offset
                      }
                  }
              }
          }
          else
          {
              instroffset = OFFSET_TRACE;         //  0xff, but not call
          }
      }
      else if (!((fRepPrefix && ((opcode & ~3) == 0x6c ||
                                 (opcode & ~3) == 0xa4 ||
                                 (opcode & ~1) == 0xaa ||
                                 (opcode & ~3) == 0xac)) ||
                                 opcode == 0xcc || opcode == 0xce))
      {
          instroffset = OFFSET_TRACE;             //  not repeated string op
      }                                           //  or int 3 / into
  
      //  if not enough bytes were read for instruction parse,
      //      just give up and trace the instruction
  
      if (cBytes < (ULONG)(InstrMem - (PUCHAR)membuf))
      {
          instroffset = OFFSET_TRACE;
      }
  
   Exit:
      //  if not tracing, compute the new instruction offset
  
      if (instroffset != OFFSET_TRACE)
      {
          instroffset += InstrMem - (PUCHAR)membuf;
      }
  
      Flat(*NextAddr) = instroffset;
      ComputeNativeAddress(NextAddr);
  }
  
  /*...........................internal function..............................*/
  /*                                                                          */
  /*                       generate a mod/rm string                           */
  /*                                                                          */
  
  void
  BaseX86MachineInfo::DIdoModrm(ProcessInfo* Process,
                                char **ppchBuf, int segOvr, BOOL fEAout)
  {
      int     mrm;                        /* modrm byte */
      char    *src;                       /* source string */
      int     sib;
      int     ss;
      int     ind;
      int     oldrm;
  
      mrm = *g_InstrMem++;                      /* get the mrm byte from instruction */
      g_MrmMod = BIT76(mrm);                   /* get mod */
      g_MrmArg = BIT53(mrm) + g_ExtendMrmReg;  /* get reg - used outside routine */
      g_MrmRm  = BIT20(mrm);                   /* get rm */
  
      if (g_MrmMod == 3)
      {
          g_MrmRm += g_ExtendRm;
  
          /* register only mode */
          if (g_XmmRegEa)
          {
              *(*ppchBuf)++ = 'x';
              *(*ppchBuf)++ = 'm';
              *(*ppchBuf)++ = 'm';
              if (g_MrmRm >= 10)
              {
                  *(*ppchBuf)++ = (char)('0' + g_MrmRm / 10);
                  g_MrmRm %= 10;
              }
              *(*ppchBuf)++ = g_MrmRm + '0';
          }
          else if (g_MmRegEa)
          {
              *(*ppchBuf)++ = 'm';
              *(*ppchBuf)++ = 'm';
              *(*ppchBuf)++ = g_MrmRm + '0';
          }
          else
          {
              if (EAsize[0] == 1)
              {
                  /* point to 8-bit register */
                  if (g_ExtendAny && g_MrmRm < 8)
                  {
                      src = g_Amd64ExtendedReg8[g_MrmRm];
                  }
                  else
                  {
                      src = g_X86Reg8[g_MrmRm];
                  }
                  X86OutputString(ppchBuf, src);
              }
              else
              {
                  src = g_X86RegBase[g_MrmRm];
                  if (g_ForceMrmReg32)
                  {
                      *(*ppchBuf)++ = 'e';
                  }
                  else if (g_OpSize > 16 &&
                           (!g_MovX || g_MrmRm >= 8))
                  {
                      /* make it a 32- or 64-bit register */
                      *(*ppchBuf)++ = (g_MrmRm >= 8 || g_OpSize == 64 && !g_MovSXD) ?
                          'r' : 'e';
                  }
                  X86OutputString(ppchBuf, src);
                  if (g_MrmRm >= 8)
                  {
                      if (g_OpSize == 32)
                      {
                          *(*ppchBuf)++ = 'd';
                      }
                      else if (g_OpSize == 16)
                      {
                          *(*ppchBuf)++ = 'w';
                      }
                  }
  
                  if (g_ControlFlow && fEAout)
                  {
                      // This is a call/jmp through a register.
                      // Output a code symbol for the target.
                      ULONG64 Target = GetReg64(g_X86RegIdx[g_MrmRm]);
                      *(*ppchBuf)++ = ' ';
                      *(*ppchBuf)++ = '{';
                      OutputSymbol(ppchBuf, (PUCHAR)&Target, g_OpSize / 8,
                                   X86_CS_OVR);
                      *(*ppchBuf)++ = '}';
                  }
              }
          }
          EAsize[0] = 0;                  //  no EA value to output
          return;
      }
  
      if (g_AddrMode == 64)
      {
          oldrm = g_MrmRm;
          if (g_MrmRm == 4)
          {
              /* g_MrmRm == 4 implies sib byte */
              sib = *g_InstrMem++;              /* get s_i_b byte */
              g_MrmRm = BIT20(sib);
          }
  
          *(*ppchBuf)++ = '[';
          if (g_MrmMod == 0 && g_MrmRm == 5)
          {
              if (g_SegAddrMode == 64 && oldrm == 5)
              {
                  // IP-relative 32-bit displacement.  The
                  // displacement is relative to the IP of the
                  // next instruction, which can't be computed
                  // yet so just put in a marker for post-processing.
                  g_X86ModrmHasIpRelOffset = TRUE;
                  g_X86IpRelOffset = *(LONG UNALIGNED *)g_InstrMem;
                  X86OutputString(ppchBuf, IPREL_MARKER);
              }
              else
              {
                  // Absolute 32-bit displacement.
                  OutputSymbol(ppchBuf, g_InstrMem, 4, segOvr);
              }
  
              g_InstrMem += 4;
          }
          else
          {
              g_MrmRm += g_ExtendRm;
  
              if (fEAout)
              {
                  if (segOvr)
                  {
                      FormSegRegAddress(&EAaddr[0], GetSegReg(segOvr),
                                        GetReg64(g_X86RegIdx[g_MrmRm]));
                      g_EaSegNames[0] = distbl[segOvr].instruct;
                  }
                  else if (g_X86RegIdx[g_MrmRm] == X86_NBP ||
                           g_X86RegIdx[g_MrmRm] == X86_NSP)
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_STACK,
                                        GetReg64(g_X86RegIdx[g_MrmRm]));
                      g_EaSegNames[0] = dszSS_;
                  }
                  else
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_DATA,
                                        GetReg64(g_X86RegIdx[g_MrmRm]));
                  }
              }
              X86OutputString(ppchBuf, g_X86Mrm64[g_MrmRm]);
          }
  
          if (oldrm == 4)
          {
              //  finish processing sib
              ind = BIT53(sib);
              if (ind != 4)
              {
                  ind += g_ExtendSibIndex;
                  *(*ppchBuf)++ = '+';
                  X86OutputString(ppchBuf, g_X86Mrm64[ind]);
                  ss = 1 << BIT76(sib);
                  if (ss != 1)
                  {
                      *(*ppchBuf)++ = '*';
                      *(*ppchBuf)++ = (char)(ss + '0');
                  }
                  if (fEAout)
                  {
                      AddrAdd(&EAaddr[0], GetReg64(g_X86RegIdx[ind]) * ss);
                  }
              }
          }
      }
      else if (g_AddrMode == 32)
      {
          oldrm = g_MrmRm;
          if (g_MrmRm == 4)
          {
              /* g_MrmRm == 4 implies sib byte */
              sib = *g_InstrMem++;              /* get s_i_b byte */
              g_MrmRm = BIT20(sib);
          }
  
          *(*ppchBuf)++ = '[';
          if (g_MrmMod == 0 && g_MrmRm == 5)
          {
              if (g_SegAddrMode == 64 && oldrm == 5)
              {
                  // IP-relative 32-bit displacement.  The
                  // displacement is relative to the IP of the
                  // next instruction, which can't be computed
                  // yet so just put in a marker for post-processing.
                  g_X86ModrmHasIpRelOffset = TRUE;
                  g_X86IpRelOffset = *(LONG UNALIGNED *)g_InstrMem;
                  X86OutputString(ppchBuf, IPREL_MARKER);
              }
              else
              {
                  // Absolute 32-bit displacement.
                  OutputSymbol(ppchBuf, g_InstrMem, 4, segOvr);
              }
  
              g_InstrMem += 4;
          }
          else
          {
              g_MrmRm += g_ExtendRm;
  
              if (fEAout)
              {
                  if (segOvr)
                  {
                      FormSegRegAddress(&EAaddr[0], GetSegReg(segOvr),
                                        EXTEND64(GetReg32(g_X86RegIdx[g_MrmRm])));
                      g_EaSegNames[0] = distbl[segOvr].instruct;
                  }
                  else if (g_X86RegIdx[g_MrmRm] == X86_NBP ||
                           g_X86RegIdx[g_MrmRm] == X86_NSP)
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_STACK,
                                        EXTEND64(GetReg32(g_X86RegIdx[g_MrmRm])));
                      g_EaSegNames[0] = dszSS_;
                  }
                  else
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_DATA,
                                        EXTEND64(GetReg32(g_X86RegIdx[g_MrmRm])));
                  }
              }
              X86OutputString(ppchBuf, g_X86Mrm32[g_MrmRm]);
          }
  
          if (oldrm == 4)
          {
              //  finish processing sib
              ind = BIT53(sib);
              if (ind != 4)
              {
                  ind += g_ExtendSibIndex;
                  *(*ppchBuf)++ = '+';
                  X86OutputString(ppchBuf, g_X86Mrm32[ind]);
                  ss = 1 << BIT76(sib);
                  if (ss != 1)
                  {
                      *(*ppchBuf)++ = '*';
                      *(*ppchBuf)++ = (char)(ss + '0');
                  }
                  if (fEAout)
                  {
                      AddrAdd(&EAaddr[0],
                              EXTEND64(GetReg32(g_X86RegIdx[ind])) * ss);
                  }
              }
          }
      }
      else
      {
          //  16-bit addressing mode
          *(*ppchBuf)++ = '[';
          if (g_MrmMod == 0 && g_MrmRm == 6)
          {
              OutputSymbol(ppchBuf, g_InstrMem, 2, segOvr);   // 16-bit offset
              g_InstrMem += 2;
          }
          else
          {
              if (fEAout)
              {
                  if (segOvr)
                  {
                      FormSegRegAddress(&EAaddr[0], GetSegReg(segOvr),
                                        GetReg16(g_X86Reg16Idx[g_MrmRm]));
                      g_EaSegNames[0] = distbl[segOvr].instruct;
                  }
                  else if (g_X86Reg16Idx[g_MrmRm] == X86_NBP)
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_STACK,
                                        GetReg16(g_X86Reg16Idx[g_MrmRm]));
                      g_EaSegNames[0] = dszSS_;
                  }
                  else
                  {
                      FormSegRegAddress(&EAaddr[0], SEGREG_DATA,
                                        GetReg16(g_X86Reg16Idx[g_MrmRm]));
                  }
                  if (g_MrmRm < 4)
                  {
                      AddrAdd(&EAaddr[0], GetReg16(g_X86Reg16Idx2[g_MrmRm]));
                  }
              }
              X86OutputString(ppchBuf, g_X86Mrm16[g_MrmRm]);
          }
      }
  
      //  output any displacement
  
      if (g_MrmMod == 1)
      {
          if (fEAout)
          {
              AddrAdd(&EAaddr[0], (long)*(char *)g_InstrMem);
          }
          OutputHexValue(ppchBuf, g_InstrMem, 1, TRUE);
          g_InstrMem++;
      }
      else if (g_MrmMod == 2)
      {
          long tmp = 0;
          if (g_AddrMode > 16)
          {
              memmove(&tmp, g_InstrMem, sizeof(long));
              if (fEAout)
              {
                  AddrAdd(&EAaddr[0], tmp);
              }
              OutputHexValue(ppchBuf, g_InstrMem, 4, TRUE);
              g_InstrMem += 4;
          }
          else
          {
              memmove(&tmp,g_InstrMem,sizeof(short));
              if (fEAout)
              {
                  AddrAdd(&EAaddr[0], tmp);
              }
              OutputHexValue(ppchBuf, g_InstrMem, 2, TRUE);
              g_InstrMem += 2;
          }
      }
  
      if (g_AddrMode == 16 && fEAout)
      {
          Off(EAaddr[0]) &= 0xffff;
          NotFlat(EAaddr[0]);
          Off(EAaddr[1]) &= 0xffff;
          NotFlat(EAaddr[1]);
          ComputeFlatAddress(&EAaddr[0], NULL);
          ComputeFlatAddress(&EAaddr[1], NULL);
      }
  
      *(*ppchBuf)++ = ']';
  
      // The value at the effective address may be pointing to an interesting
      // symbol, as with indirect jumps or memory operations.
      // If there's an EA and an exact symbol match, display
      // the extra symbol.
      if (fEAout)
      {
          DWORD64 symbol;
  
          if (m_Target->
              ReadPointer(Process, this, Flat(EAaddr[0]), &symbol) == S_OK)
          {
              char* pchBuf = *ppchBuf;
  
              (*ppchBuf)++;
              if (OutputExactSymbol(ppchBuf, (PUCHAR)&symbol,
                                    m_Ptr64 ? 8 : 4, segOvr))
              {
                  *pchBuf = '{';
                  *(*ppchBuf)++ = '}';
              }
              else
              {
                  (*ppchBuf)--;
              }
          }
      }
  }
  
  LONGLONG
  GetSignExtendedValue(int OpLen, PUCHAR Mem)
  {
      switch(OpLen)
      {
      case 1:
          return *(char *)Mem;
      case 2:
          return *(short UNALIGNED *)Mem;
      case 4:
          return *(long UNALIGNED *)Mem;
      case 8:
          return *(LONGLONG UNALIGNED *)Mem;
      }
  
      DBG_ASSERT(FALSE);
      return 0;
  }
  
  /*** OutputHexValue - output hex value
  *  07-Jun-1999 -by- Andre Vachon
  *   Purpose:
  *       Output the value pointed by *ppchBuf of the specified
  *       length.  The value is treated as signed and leading
  *       zeroes are not printed.  The string is prefaced by a
  *       '+' or '-' sign as appropriate.
  *
  *   Input:
  *       *ppchBuf - pointer to text buffer to fill
  *       *pchMemBuf - pointer to memory buffer to extract value
  *       length - length in bytes of value (1, 2, and 4 supported)
  *       fDisp - set if displacement to output '+'
  *
  *   Output:
  *       *ppchBuf - pointer updated to next text character
  *
  *************************************************************************/
  
  void
  OutputHexValue (char **ppchBuf, PUCHAR pchMemBuf, int length, int fDisp)
  {
      LONGLONG value;
      int index;
      char digit[32];
  
      value = GetSignExtendedValue(length, pchMemBuf);
  
      length <<= 1;               //  shift once to get hex length
  
      if (value != 0 || !fDisp)
      {
          if (fDisp)
          {
              //  use neg value for byte displacement
              //  assume very large DWORDs are negative too
              if (value < 0 &&
                  (length == 2 ||
                   ((unsigned long)value & 0xff000000) == 0xff000000))
              {
                  value = -value;
                  *(*ppchBuf)++ = '-';
              }
              else
              {
                  *(*ppchBuf)++ = '+';
              }
          }
  
          *(*ppchBuf)++ = '0';
          *(*ppchBuf)++ = 'x';
          for (index = length - 1; index != -1; index--)
          {
              digit[index] = (char)(value & 0xf);
              value >>= 4;
          }
          index = 0;
          while (digit[index] == 0 && index < length - 1)
          {
              index++;
          }
          while (index < length)
          {
              *(*ppchBuf)++ = hexdigit[digit[index++]];
          }
      }
  }
  
  void
  OutputExHexValue(char **ppchBuf, PUCHAR pchMemBuf, int MemLen, int OpLen)
  {
      LONGLONG Value = GetSignExtendedValue(MemLen, pchMemBuf);
      OutputHexValue(ppchBuf, (PUCHAR)&Value, OpLen, FALSE);
  }
  
  /*** OutputHexString - output hex string
  *
  *   Purpose:
  *       Output the value pointed by *ppchMemBuf of the specified
  *       length.  The value is treated as unsigned and leading
  *       zeroes are printed.
  *
  *   Input:
  *       *ppchBuf - pointer to text buffer to fill
  *       *pchValue - pointer to memory buffer to extract value
  *       length - length in bytes of value
  *
  *   Output:
  *       *ppchBuf - pointer updated to next text character
  *       *ppchMemBuf - pointer update to next memory byte
  *
  *************************************************************************/
  
  void
  OutputHexString (char **ppchBuf, PUCHAR pchValue, int length)
  {
      UCHAR chMem;
  
      pchValue += length;
      while (length--)
      {
          chMem = *--pchValue;
          *(*ppchBuf)++ = hexdigit[chMem >> 4];
          *(*ppchBuf)++ = hexdigit[chMem & 0x0f];
      }
  }
  
  /*** OutputHexCode - output hex code
  *
  *   Purpose:
  *       Output the code pointed by pchMemBuf of the specified
  *       length.  The value is treated as unsigned and leading
  *       zeroes are printed.  This differs from OutputHexString
  *       in that bytes are printed from low to high addresses.
  *
  *   Input:
  *       *ppchBuf - pointer to text buffer to fill
  *       pchMemBuf - pointer to memory buffer to extract value
  *       length - length in bytes of value
  *
  *   Output:
  *       *ppchBuf - pointer updated to next text character
  *
  *************************************************************************/
  
  void OutputHexCode (char **ppchBuf, PUCHAR pchMemBuf, int length)
  {
      UCHAR chMem;
  
      while (length--)
      {
          chMem = *pchMemBuf++;
          *(*ppchBuf)++ = hexdigit[chMem >> 4];
          *(*ppchBuf)++ = hexdigit[chMem & 0x0f];
      }
  }
  
  /*** X86OutputString - output string
  *
  *   Purpose:
  *       Copy the string into the buffer pointed by *ppBuf.
  *
  *   Input:
  *       *pStr - pointer to string
  *
  *   Output:
  *       *ppBuf points to next character in buffer.
  *
  *************************************************************************/
  
  void
  X86OutputString (
      char **ppBuf,
      char *pStr
      )
  {
      while (*pStr)
      {
          *(*ppBuf)++ = *pStr++;
      }
  }
  
  
  /*** OutputSymbol - output symbolic value
  *
  *   Purpose:
  *       Output the value in outvalue into the buffer
  *       pointed by *pBuf.  Express the value as a
  *       symbol plus displacment, if possible.
  *
  *   Input:
  *       *ppBuf - pointer to text buffer to fill
  *       *pValue - pointer to memory buffer to extract value
  *       length - length in bytes of value
  *
  *   Output:
  *       *ppBuf - pointer updated to next text character
  *
  *************************************************************************/
  
  void
  BaseX86MachineInfo::OutputSymbol (
      char **ppBuf,
      PUCHAR pValue,
      int length,
      int segOvr
      )
  {
      CHAR   chSymbol[MAX_SYMBOL_LEN];
      ULONG64 displacement;
      ULONG64 value;
  
      value = 0;
      memcpy(&value, pValue, length);
      if (length == 4)
      {
          value = EXTEND64(value);
      }
  
      if (IS_CONTEXT_POSSIBLE(m_Target))
      {
          FormSegRegAddress(&EAaddr[0], GetSegReg(segOvr), value);
          value = Flat(EAaddr[0]);
      }
  
      GetSymbol(value, chSymbol, sizeof(chSymbol), &displacement);
      if (chSymbol[0])
      {
          X86OutputString(ppBuf, chSymbol);
          OutputHexValue(ppBuf, (PUCHAR)&displacement, length, TRUE);
          *(*ppBuf)++ = ' ';
          *(*ppBuf)++ = '(';
          OutputHexString(ppBuf, pValue, length);
          *(*ppBuf)++ = ')';
      }
      else
      {
          OutputHexString(ppBuf, pValue, length);
      }
  }
  
  /*** OutputExactSymbol - Output symbolic value only for exact symbol
  *                        matches.
  *
  *************************************************************************/
  
  BOOL
  BaseX86MachineInfo::OutputExactSymbol (
      char **ppBuf,
      PUCHAR pValue,
      int length,
      int segOvr
      )
  {
      CHAR   chSymbol[MAX_SYMBOL_LEN];
      ULONG64 displacement;
      ULONG64 value;
  
      value = 0;
      memcpy(&value, pValue, length);
      if (length == 4)
      {
          value = EXTEND64(value);
      }
  
      GetSymbol(value, chSymbol, sizeof(chSymbol), &displacement);
      if (chSymbol[0] && displacement == 0)
      {
          X86OutputString(ppBuf, chSymbol);
          OutputHexValue(ppBuf, (PUCHAR)&displacement, length, TRUE);
          *(*ppBuf)++ = ' ';
          *(*ppBuf)++ = '(';
          OutputHexString(ppBuf, pValue, length);
          *(*ppBuf)++ = ')';
          return TRUE;
      }
      else
      {
          return FALSE;
      }
  }
  
  void
  OutputHexAddr(PSTR *ppBuffer, PADDR paddr)
  {
      sprintAddr(ppBuffer, paddr);
      // Remove trailing space.
      (*ppBuffer)--;
      **ppBuffer = 0;
  }
  
  ULONG
  BaseX86MachineInfo::GetSegReg(int SegOpcode)
  {
      switch(SegOpcode)
      {
      case 0x26:
          return SEGREG_ES;
      case X86_CS_OVR:
          return SEGREG_CODE;
      case 0x36:
          return SEGREG_STACK;
      case 0x64:
          return SEGREG_FS;
      case 0x65:
          return SEGREG_GS;
      case 0x3e:
      default:
          return SEGREG_DATA;
      }
  }
  
  int
  BaseX86MachineInfo::ComputeJccEa(int Opcode, BOOL EaOut)
  {
      if (!EaOut)
      {
          return JCC_EA_NONE;
      }
  
      ULONG Flags;
      int Branch;
  
      if ((Opcode >= 0x70 && Opcode <= 0x7f) ||
          (Opcode >= 0x180 && Opcode <= 0x18f))
      {
          int Table = (Opcode >> 1) & 7;
  
          Flags = GetReg32(X86_NFL);
          Branch = Opcode & 1;
          if ((Flags & g_JccCheckTable[Table][0]) != 0 ||
              ((Flags >> g_JccCheckTable[Table][1]) & 1) !=
              ((Flags >> g_JccCheckTable[Table][2]) & 1))
          {
              Branch ^= 1;
          }
  
          return JCC_EA_NO_BRANCH + Branch;
      }
      else
      {
          ULONG64 Cx = GetReg64(X86_NCX);
          switch(g_OpSize)
          {
          case 16:
              Cx &= 0xffff;
              break;
          case 32:
              Cx &= 0xffffffff;
              break;
          }
  
          switch(Opcode)
          {
          case 0xe0: // LOOPNE.
              Flags = GetReg32(X86_NFL);
              Branch = (Flags & X86_BIT_FLAGZF) == 0 && Cx != 1 ?
                  JCC_EA_BRANCH : JCC_EA_NO_BRANCH;
              break;
          case 0xe1: // LOOPE.
              Flags = GetReg32(X86_NFL);
              Branch = (Flags & X86_BIT_FLAGZF) != 0 && Cx != 1 ?
                  JCC_EA_BRANCH : JCC_EA_NO_BRANCH;
              break;
          case 0xe2: // LOOP.
              Branch = Cx == 1 ? JCC_EA_NO_BRANCH : JCC_EA_BRANCH;
              break;
          case 0xe3: // J*CXZ.
              Branch = Cx == 0 ? JCC_EA_BRANCH : JCC_EA_NO_BRANCH;
              break;
          default:
              DBG_ASSERT(FALSE);
              Branch = JCC_EA_NONE;
              break;
          }
  
          return Branch;
      }
  }
  
  BOOL
  BaseX86MachineInfo::IsBreakpointInstruction(ProcessInfo* Process, PADDR Addr)
  {
      UCHAR Instr[X86_INT3_LEN];
  
      if (fnotFlat(*Addr) ||
          m_Target->ReadAllVirtual(Process, Flat(*Addr),
                                   Instr, X86_INT3_LEN) != S_OK)
      {
          return FALSE;
      }
  
      return !memcmp(Instr, g_X86Int3, X86_INT3_LEN);
  }
  
  HRESULT
  BaseX86MachineInfo::InsertBreakpointInstruction(PUSER_DEBUG_SERVICES Services,
                                                  ULONG64 Process,
                                                  ULONG64 Offset,
                                                  ULONG Flags,
                                                  PUCHAR SaveInstr,
                                                  PULONG64 ChangeStart,
                                                  PULONG ChangeLen)
  {
      if (Flags != IBI_DEFAULT)
      {
          return E_INVALIDARG;
      }
  
      if ((m_Target->m_MachineType != IMAGE_FILE_MACHINE_I386) &&
          (g_Wow64exts != NULL))
      {
          ProcessInfo* ProcInfo = m_Target->FindProcessByHandle(Process);
          if (ProcInfo != NULL)
          {
              (*g_Wow64exts)(WOW64EXTS_FLUSH_CACHE_WITH_HANDLE,
                             ProcInfo->m_SysHandle, Offset, X86_INT3_LEN);
          }
      }
  
      *ChangeStart = Offset;
      *ChangeLen = X86_INT3_LEN;
  
      ULONG Done;
      HRESULT Status;
  
      Status = Services->ReadVirtual(Process, Offset, SaveInstr,
                                     X86_INT3_LEN, &Done);
      if (Status == S_OK && Done != X86_INT3_LEN)
      {
          Status = HRESULT_FROM_WIN32(ERROR_READ_FAULT);
      }
  
      if (Status == S_OK)
      {
          Status = Services->WriteVirtual(Process, Offset, g_X86Int3,
                                          X86_INT3_LEN, &Done);
          if (Status == S_OK && Done != X86_INT3_LEN)
          {
              Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
          }
      }
  
      return Status;
  }
  
  HRESULT
  BaseX86MachineInfo::RemoveBreakpointInstruction(PUSER_DEBUG_SERVICES Services,
                                                  ULONG64 Process,
                                                  ULONG64 Offset,
                                                  PUCHAR SaveInstr,
                                                  PULONG64 ChangeStart,
                                                  PULONG ChangeLen)
  {
      if ((m_Target->m_MachineType != IMAGE_FILE_MACHINE_I386) &&
          (g_Wow64exts != NULL))
      {
          ProcessInfo* ProcInfo = m_Target->FindProcessByHandle(Process);
          if (ProcInfo != NULL)
          {
              (*g_Wow64exts)(WOW64EXTS_FLUSH_CACHE_WITH_HANDLE,
                             ProcInfo->m_SysHandle, Offset, X86_INT3_LEN);
          }
      }
  
      *ChangeStart = Offset;
      *ChangeLen = X86_INT3_LEN;
  
      ULONG Done;
      HRESULT Status;
  
      Status = Services->WriteVirtual(Process, Offset, SaveInstr,
                                      X86_INT3_LEN, &Done);
      if (Status == S_OK && Done != X86_INT3_LEN)
      {
          Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
      }
      return Status;
  }
  
  void
  BaseX86MachineInfo::AdjustPCPastBreakpointInstruction(PADDR Addr,
                                                        ULONG BreakType)
  {
      if (BreakType == DEBUG_BREAKPOINT_CODE)
      {
          AddrAdd(Addr, X86_INT3_LEN);
          SetPC(Addr);
      }
  }
  
  BOOL
  BaseX86MachineInfo::IsCallDisasm(PCSTR Disasm)
  {
      return strstr(Disasm, " call") != NULL;
  }
  
  BOOL
  BaseX86MachineInfo::IsReturnDisasm(PCSTR Disasm)
  {
      return strstr(Disasm, " ret") != NULL ||
          (IS_KERNEL_TARGET(m_Target) && strstr(Disasm, " iretd") != NULL);
  }
  
  BOOL
  BaseX86MachineInfo::IsSystemCallDisasm(PCSTR Disasm)
  {
      return (strstr(Disasm, " int ") != NULL &&
              strstr(Disasm, " 2e") != NULL) ||
          strstr(Disasm, " sysenter") != NULL ||
          strstr(Disasm, " syscall") != NULL;
  }
  
  BOOL
  BaseX86MachineInfo::IsDelayInstruction(PADDR Addr)
  {
      // X86 does not have delay slots.
      return FALSE;
  }
  
  void
  BaseX86MachineInfo::GetEffectiveAddr(PADDR Addr, PULONG Size)
  {
      *Addr = EAaddr[0];
      *Size = EAsize[0];
  }
  
  void
  BaseX86MachineInfo::IncrementBySmallestInstruction(PADDR Addr)
  {
      AddrAdd(Addr, 1);
  }
  
  void
  BaseX86MachineInfo::DecrementBySmallestInstruction(PADDR Addr)
  {
      AddrSub(Addr, 1);
  }
  
  //----------------------------------------------------------------------------
  //
  // X86MachineInfo methods.
  //
  //----------------------------------------------------------------------------
  
  HRESULT
  X86MachineInfo::NewBreakpoint(DebugClient* Client,
                                ULONG Type,
                                ULONG Id,
                                Breakpoint** RetBp)
  {
      HRESULT Status;
  
      switch(Type & (DEBUG_BREAKPOINT_CODE | DEBUG_BREAKPOINT_DATA))
      {
      case DEBUG_BREAKPOINT_CODE:
          *RetBp = new CodeBreakpoint(Client, Id, IMAGE_FILE_MACHINE_I386);
          Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
          break;
      case DEBUG_BREAKPOINT_DATA:
          *RetBp = new X86DataBreakpoint(Client, Id, X86_CR4, X86_DR6,
                                         IMAGE_FILE_MACHINE_I386);
          Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
          break;
      default:
          // Unknown breakpoint type.
          Status = E_NOINTERFACE;
      }
  
      return Status;
  }
  
  void
  X86MachineInfo::InsertThreadDataBreakpoints(void)
  {
      ULONG Dr7Value;
  
      BpOut("Thread %d data breaks %d\n",
            g_Thread->m_UserId, g_Thread->m_NumDataBreaks);
  
      // Start with all breaks turned off.
      Dr7Value = GetIntReg(X86_DR7) & ~X86_DR7_CTRL_03_MASK;
  
      if (g_Thread->m_NumDataBreaks > 0)
      {
          ULONG i;
  
          for (i = 0; i < g_Thread->m_NumDataBreaks; i++)
          {
              X86DataBreakpoint* Bp =
                  (X86DataBreakpoint *)g_Thread->m_DataBreakBps[i];
  
              ULONG64 Addr = Flat(*Bp->GetAddr());
              BpOut("  dbp %d at %p\n", i, Addr);
              if (g_DataBreakpointsChanged)
              {
                  SetReg32(X86_DR0 + i, (ULONG)Addr);
              }
              // There are two enable bits per breakpoint
              // and four len/rw bits so split up enables
              // and len/rw when shifting into place.
              Dr7Value |=
                  ((Bp->m_Dr7Bits & 0xffff0000) << (i * 4)) |
                  ((Bp->m_Dr7Bits & X86_DR7_ALL_ENABLES) << (i * 2));
          }
  
          // The kernel automatically clears DR6 when it
          // processes a DBGKD_CONTROL_SET.
          if (IS_USER_TARGET(m_Target))
          {
              SetReg32(X86_DR6, 0);
          }
  
          // Set local exact match, which is effectively global on NT.
          Dr7Value |= X86_DR7_LOCAL_EXACT_ENABLE;
              }
  
      BpOut("  thread %d DR7 %X\n", g_Thread->m_UserId, Dr7Value);
      SetReg32(X86_DR7, Dr7Value);
  }
  
  void
  X86MachineInfo::RemoveThreadDataBreakpoints(void)
  {
      SetReg32(X86_DR7, 0);
  }
  
  ULONG
  X86MachineInfo::IsBreakpointOrStepException(PEXCEPTION_RECORD64 Record,
                                              ULONG FirstChance,
                                              PADDR BpAddr,
                                              PADDR RelAddr)
  {
      if (Record->ExceptionCode == STATUS_BREAKPOINT ||
          Record->ExceptionCode == STATUS_WX86_BREAKPOINT)
      {
          // Data breakpoints hit as STATUS_SINGLE_STEP so
          // this can only be a code breakpoint.
          if (IS_USER_TARGET(m_Target) && FirstChance)
          {
              // Back up to the actual breakpoint instruction.
              AddrSub(BpAddr, X86_INT3_LEN);
              SetPC(BpAddr);
          }
          return EXBS_BREAKPOINT_CODE;
      }
      else if (Record->ExceptionCode == STATUS_SINGLE_STEP ||
               Record->ExceptionCode == STATUS_WX86_SINGLE_STEP)
      {
          // XXX t-tcheng - Conversion for Dr6, Dr7 not implemented yet...
  
          ULONG Dr6 = GetIntReg(X86_DR6);
          ULONG Dr7 = GetIntReg(X86_DR7);
  
          BpOut("X86 step: DR6 %X, DR7 %X\n", Dr6, Dr7);
  
          // The single step bit should always be clear if a data breakpoint
          // is hit but also check the DR7 enables just in case.
          // We've also seen cases where DR6 shows no hits, so consider
          // that a single step also.
          if ((Dr6 & X86_DR6_SINGLE_STEP) || (Dr7 & X86_DR7_ALL_ENABLES) == 0 ||
              (Dr6 & X86_DR6_BREAK_03) == 0)
          {
              // There's no way to tell if this particular
              // step was a branch step or not so only
              // try to look up the branch source if we're
              // in branch-trace mode.
              if (m_SupportsBranchTrace &&
                  g_CmdState == 'b')
              {
                  HRESULT Status;
                  ULONG64 LastIp;
  
                  // The Pentium IV handles last-branch tracking
                  // differently from the P6.
                  if (m_Target->m_FirstProcessorId.X86.Family >= 15)
                  {
                      ULONG64 LbrTos;
  
                      Status = m_Target->ReadMsr(X86_MSR_LAST_BRANCH_TOS,
                                                 &LbrTos);
                      if (Status == S_OK)
                      {
                          Status = m_Target->ReadMsr(X86_MSR_LAST_BRANCH_0 +
                                                     (ULONG)LbrTos,
                                                     &LastIp);
                          // The result is a 64-bit value with the
                          // from address in the upper 32-bits.
                          LastIp >>= 32;
                      }
                  }
                  else
                  {
                      Status = m_Target->ReadMsr(X86_MSR_LAST_BRANCH_FROM_IP,
                                                 &LastIp);
                  }
  
                  if (Status == S_OK)
                  {
                      // The branch may have come from a different
                      // segment.  We could try and determine what
                      // code segment it was by reading the stack to
                      // get the saved CS value but it's not worth
                      // it right now.
                      FormAddr(SEGREG_CODE, EXTEND64(LastIp),
                               FORM_CODE | FORM_SEGREG |
                               X86_FORM_VM86(GetIntReg(X86_EFL)),
                               RelAddr);
                  }
              }
  
              // This is a true single step exception, not
              // a data breakpoint.
              return EXBS_STEP_INSTRUCTION;
          }
          else
          {
              // Some data breakpoint must be hit.
              // There doesn't appear to be any way to get the
              // faulting instruction address so just leave the PC.
              return EXBS_BREAKPOINT_DATA;
          }
      }
  
      return EXBS_NONE;
  }
  
  void
  X86MachineInfo::PrintStackFrameAddressesTitle(ULONG Flags)
  {
      PrintMultiPtrTitle("ChildEBP", 1);
      PrintMultiPtrTitle("RetAddr", 1);
  }
  
  void
  X86MachineInfo::PrintStackFrameAddresses(ULONG Flags,
                                           PDEBUG_STACK_FRAME StackFrame)
  {
      dprintf("%s %s ",
          FormatAddr64(StackFrame->FrameOffset),
          FormatAddr64(StackFrame->ReturnOffset));
  }
  
  void
  X86MachineInfo::PrintStackArgumentsTitle(ULONG Flags)
  {
      PrintMultiPtrTitle("Args to Child", 3);
  }
  
  void
  X86MachineInfo::PrintStackArguments(ULONG Flags,
                                      PDEBUG_STACK_FRAME StackFrame)
  {
      dprintf("%s %s %s ",
              FormatAddr64(StackFrame->Params[0]),
              FormatAddr64(StackFrame->Params[1]),
              FormatAddr64(StackFrame->Params[2]));
  }
  
  void
  X86MachineInfo::PrintStackCallSiteTitle(ULONG Flags)
  {
  }
  
  void
  X86MachineInfo::PrintStackCallSite(ULONG Flags,
                                     PDEBUG_STACK_FRAME StackFrame,
                                     PSYMBOL_INFO SiteSymbol,
                                     PSTR SymName,
                                     DWORD64 Displacement)
  {
      // Truncate the displacement to 32 bits since it can never be
      // greater than 32 bit for X86, and we don't want addresses with no
      // symbols to show up with the leading 0xfffffff
  
      MachineInfo::PrintStackCallSite(Flags, StackFrame, SiteSymbol, SymName,
                                      (DWORD64)(DWORD)Displacement);
  
      if (!(Flags & DEBUG_STACK_FUNCTION_INFO))
      {
          return;
      }
  
      if (StackFrame->FuncTableEntry)
      {
          PFPO_DATA FpoData = (PFPO_DATA)StackFrame->FuncTableEntry;
          switch(FpoData->cbFrame)
          {
          case FRAME_FPO:
              if (FpoData->fHasSEH)
              {
                  dprintf(" (FPO: [SEH])");
              }
              else
              {
                  dprintf(" (FPO:");
                  if (FpoData->fUseBP)
                  {
                      dprintf(" [EBP 0x%s]",
                              FormatAddr64(SAVE_EBP(StackFrame)));
                  }
                  dprintf(" [%d,%d,%d])",
                          FpoData->cdwParams,
                          FpoData->cdwLocals,
                          FpoData->cbRegs);
              }
              break;
  
          case FRAME_NONFPO:
              dprintf(" (FPO: [Non-Fpo])" );
              break;
  
          case FRAME_TRAP:
              if (!IS_KERNEL_TARGET(m_Target))
              {
                  goto UnknownFpo;
              }
  
              dprintf(" (FPO: [%d,%d] TrapFrame%s @ %s)",
                      FpoData->cdwParams,
                      FpoData->cdwLocals,
                      TRAP_EDITED(StackFrame) ? "" : "-EDITED",
                      FormatAddr64(SAVE_TRAP(StackFrame)));
              break;
  
          case FRAME_TSS:
              if (!IS_KERNEL_TARGET(m_Target))
              {
                  goto UnknownFpo;
              }
  
              dprintf(" (FPO: TaskGate %lx:0)",
                      (ULONG)TRAP_TSS(StackFrame));
              break;
  
          default:
          UnknownFpo:
              dprintf(" (UNKNOWN FPO TYPE)");
              break;
          }
      }
  
      if (SiteSymbol->Tag == SymTagFunction)
      {
          ULONG CallConv;
  
          // Look up the type symbol for the function.
          if (SymGetTypeInfo(g_Process->m_SymHandle,
                             SiteSymbol->ModBase,
                             SiteSymbol->TypeIndex,
                             TI_GET_CALLING_CONVENTION,
                             &CallConv) &&
              CallConv < CV_CALL_RESERVED)
          {
              dprintf(" (CONV: %s)", g_CallConv[CallConv]);
          }
      }
  }
  
  void
  X86MachineInfo::PrintStackFrameMemoryUsage(PDEBUG_STACK_FRAME CurFrame,
                                             PDEBUG_STACK_FRAME PrevFrame)
  {
      if (CurFrame->FrameOffset >= PrevFrame->FrameOffset)
      {
          dprintf(" %6x ",
                  (ULONG)(CurFrame->FrameOffset - PrevFrame->FrameOffset));
      }
      else
      {
          dprintf("        ");
      }
  }
  