context: /*
   *$Log:	fixwild.c,v $
   * Revision 1.10  93/10/28  11:10:10  emmerik
   * Addressing mode [reg+nnnn] is now wildcarded
   * 
   * Revision 1.9  93/10/26  13:40:11  cifuente
   * op0F(byte pat[])
   * 
   * Revision 1.8  93/10/26  13:01:29  emmerik
   * Completed the odd opcodes, like 0F XX and F7. Result: some library
   * functions that were not recognised before are recognised now.
   * 
   * Revision 1.7  93/10/11  11:37:01  cifuente
   * First walk of HIGH_LEVEL icodes.
   * 
   * Revision 1.6  93/10/01  14:36:21  emmerik
   * Added $ log, and made independant of dcc.h
   * 
   *
   */
  
  /*  *   *   *   *   *   *   *   *   *   *   *  *\
  *                                               *
  *           Fix Wild Cards Code                 *
  *                                               *
  \*  *   *   *   *   *   *   *   *   *   *   *  */
  
  class FixWild
  {
      private const int PATLEN = 23;
      private const byte WILD = 0xF4;
  
      private const bool TRUE = true;
      private const bool FALSE = false;
  
      int pc;                              /* Indexes into pat[] */
  
      /* prototypes */
      //static bool ModRM(byte[] pat);              /* Handle the mod/rm byte */
      //static bool TwoWild(byte[] pat);            /* Make the next 2 bytes wild */
      //static bool FourWild(byte[] pat);           /* Make the next 4 bytes wild */
      //void fixWildCards(byte[] pat);       /* Main routine */
  
  
      /* Handle the mod/rm case. Returns true if pattern exhausted */
      bool ModRM(byte[] pat)
      {
          byte op;
  
          /* A standard mod/rm byte follows opcode */
          op = pat[pc++];                         /* The mod/rm byte */
          if (pc >= PATLEN) return TRUE;          /* Skip Mod/RM */
          switch (op & 0xC0)
          {
          case 0x00:                          /* [reg] or [nnnn] */
              if ((op & 0xC7) == 6)
              {
                  /* Uses [nnnn] address mode */
                  pat[pc++] = WILD;
                  if (pc >= PATLEN) return TRUE;
                  pat[pc++] = WILD;
                  if (pc >= PATLEN) return TRUE;
              }
              break;
          case 0x40:                          /* [reg + nn] */
              if ((pc += 1) >= PATLEN) return TRUE;
              break;
          case 0x80:                          /* [reg + nnnn] */
              /* Possibly just a long constant offset from a register,
                  but often will be an index from a variable */
              pat[pc++] = WILD;
              if (pc >= PATLEN) return TRUE;
              pat[pc++] = WILD;
              if (pc >= PATLEN) return TRUE;
              break;
          case 0xC0:                          /* reg */
              break;
          }
          return FALSE;
      }
  
      /* Change the next two bytes to wild cards */
      bool TwoWild(byte[] pat)
      {
          pat[pc++] = WILD;
          if (pc >= PATLEN) return TRUE;      /* Pattern exhausted */
          pat[pc++] = WILD;
          if (pc >= PATLEN) return TRUE;
          return FALSE;
      }
  
      /* Change the next four bytes to wild cards */
      bool FourWild(byte[] pat)
      {
          TwoWild(pat);
          return TwoWild(pat);
      }
  
      /* Chop from the current point by wiping with zeroes. Can't rely on anything
          after this point */
      void chop(byte[] pat)
      {
          if (pc >= PATLEN) return;               /* Could go negative otherwise */
          for (int i = pc; i < pat.Length; ++i)
              pat[i] = 0;
      }
  
      bool op0F(byte[] pat)
      {
          /* The two byte opcodes */
          byte op = pat[pc++];
          switch (op & 0xF0)
          {
          case 0x00:              /* 00 - 0F */
              if (op >= 0x06)     /* Clts, Invd, Wbinvd */
                  return false;
              else
              {
                  /* Grp 6, Grp 7, LAR, LSL */
                  return ModRM(pat);
              }
          case 0x20:              /* Various funnies, all with Mod/RM */
              return ModRM(pat);
  
          case 0x80:
              pc += 2;            /* Word displacement cond jumps */
              return false;
  
          case 0x90:              /* Byte set on condition */
              return ModRM(pat);
  
          case 0xA0:
              switch (op)
              {
              case 0xA0:      /* Push FS */
              case 0xA1:      /* Pop  FS */
              case 0xA8:      /* Push GS */
              case 0xA9:      /* Pop  GS */
                  return false;
  
              case 0xA3:      /* Bt  Ev,Gv */
              case 0xAB:      /* Bts Ev,Gv */
                  return ModRM(pat);
  
              case 0xA4:      /* Shld EvGbIb */
              case 0xAC:      /* Shrd EvGbIb */
                  if (ModRM(pat))
                      return true;
                  pc++;       /* The #num bits to shift */
                  return false;
  
              case 0xA5:      /* Shld EvGb CL */
              case 0xAD:      /* Shrd EvGb CL */
                  return ModRM(pat);
  
              default:        /* CmpXchg, Imul */
                  return ModRM(pat);
              }
  
          case 0xB0:
              if (op == 0xBA)
              {
                  /* Grp 8: bt/bts/btr/btc Ev,#nn */
                  if (ModRM(pat))
                      return true;
                  pc++;           /* The #num bits to shift */
                  return false;
              }
              return ModRM(pat);
  
          case 0xC0:
              if (op <= 0xC1)
              {
                  /* Xadd */
                  return ModRM(pat);
              }
              /* Else BSWAP */
              return false;
  
          default:
              return false;       /* Treat as double byte opcodes */
          }
      }
  
      /* Scan through the instructions in pat[], looking for opcodes that may
          have operands that vary with different instances. For example, load and
          store from statics, calls to other procs (even relative calls; they may
          call procs loaded in a different order, etc).
          Note that this procedure is architecture specific, and assumes the
          processor is in 16 bit address mode (real mode).
          PATLEN bytes are scanned.
      */
      public void fixWildCards(byte[] pat)
      {
          byte op;
          int quad;
          byte intArg;
  
          pc = 0;
          while (pc < PATLEN)
          {
              op = pat[pc++];
              if (pc >= PATLEN) return;
  
              quad = op & 0xC0;                   /* Quadrant of the opcode map */
              if (quad == 0)
              {
                  /* Arithmetic group 00-3F */
  
                  if ((op & 0xE7) == 0x26)        /* First check for the odds */
                  {
                      /* Segment prefix: treat as 1 byte opcode */
                      continue;
                  }
                  if (op == 0x0F)                 /* 386 2 byte opcodes */
                  {
                      if (op0F(pat)) return;
                      continue;
                  }
  
                  if ((op & 0x04) != 0)
                  {
                      /* All these are constant. Work out the instr length */
                      if ((op & 2) != 0)
                      {
                          /* Push, pop, other 1 byte opcodes */
                          continue;
                      }
                      else
                      {
                          if ((op & 1) != 0)
                          {
                              /* Word immediate operands */
                              pc += 2;
                              continue;
                          }
                          else
                          {
                              /* Byte immediate operands */
                              pc++;
                              continue;
                          }
                      }
                  }
                  else
                  {
                      /* All these have mod/rm bytes */
                      if (ModRM(pat)) return;
                      continue;
                  }
              }
              else if (quad == 0x40)
              {
                  if ((op & 0x60) == 0x40)
                  {
                      /* 0x40 - 0x5F -- these are inc, dec, push, pop of general
                          registers */
                      continue;
                  }
                  else
                  {
                      /* 0x60 - 0x70 */
                      if ((op & 0x10) != 0)
                      {
                          /* 70-7F 2 byte jump opcodes */
                          pc++;
                          continue;
                      }
                      else
                      {
                          /* Odds and sods */
                          switch (op)
                          {
                          case 0x60:  /* pusha */
                          case 0x61:  /* popa */
                          case 0x64:  /* overrides */
                          case 0x65:
                          case 0x66:
                          case 0x67:
                          case 0x6C:  /* insb DX */
                          case 0x6E:  /* outsb DX */
                              continue;
  
                          case 0x62:  /* bound */
                              pc += 4;
                              continue;
  
                          case 0x63:  /* arpl */
                              if (TwoWild(pat)) return;
                              continue;
  
                          case 0x68:  /* Push byte */
                          case 0x6A:  /* Push byte */
                          case 0x6D:  /* insb port */
                          case 0x6F:  /* outsb port */
                              /* 2 byte instr, no wilds */
                              pc++;
                              continue;
  
                          }
                      }
  
                  }
              }
              else if (quad == 0x80)
              {
                  switch (op & 0xF0)
                  {
                  case 0x80:          /* 80 - 8F */
                      /* All have a mod/rm byte */
                      if (ModRM(pat)) return;
                      /* These also have immediate values */
                      switch (op)
                      {
                      case 0x80:
                      case 0x83:
                          /* One byte immediate */
                          pc++;
                          continue;
  
                      case 0x81:
                          /* Immediate 16 bit values might be constant, but
                              also might be relocatable. Have to make them
                              wild */
                          if (TwoWild(pat)) return;
                          continue;
                      }
                      continue;
                  case 0x90:          /* 90 - 9F */
                      if (op == 0x9A)
                      {
                          /* far call */
                          if (FourWild(pat)) return;
                          continue;
                      }
                      /* All others are 1 byte opcodes */
                      continue;
                  case 0xA0:          /* A0 - AF */
                      if ((op & 0x0C) == 0)
                      {
                          /* mov al/ax to/from [nnnn] */
                          if (TwoWild(pat)) 
                              return;
                      }
                      else if ((op & 0xFE) == 0xA8)
                      {
                          /* test al,#byte or test ax,#word */
                          if ((op & 1)!=0)
                              pc += 2;
                          else
                              pc += 1;
                      }
                      continue;
                  case 0xB0:          /* B0 - BF */
                      {
                          if ((op & 8) != 0)
                          {
                              /* mov reg, #16 */
                              /* Immediate 16 bit values might be constant, but also
                                  might be relocatable. For now, make them wild */
                              if (TwoWild(pat)) return;
                          }
                          else
                          {
                              /* mov reg, #8 */
                              pc++;
                          }
                          continue;
                      }
                  }
              }
              else
              {
                  /* In the last quadrant of the op code table */
                  switch (op)
                  {
                  case 0xC0:          /* 386: Rotate group 2 ModRM, byte, #byte */
                  case 0xC1:          /* 386: Rotate group 2 ModRM, word, #byte */
                      if (ModRM(pat)) return;
                      /* Byte immediate value follows ModRM */
                      pc++;
                      continue;
  
                  case 0xC3:          /* Return */
                  case 0xCB:          /* Return far */
                      chop(pat);
                      return;
                  case 0xC2:          /* Ret nnnn */
                  case 0xCA:          /* Retf nnnn */
                      pc += 2;
                      chop(pat);
                      return;
  
                  case 0xC4:          /* les Gv, Mp */
                  case 0xC5:          /* lds Gv, Mp */
                      if (ModRM(pat)) return;
                      continue;
  
                  case 0xC6:          /* Mov ModRM, #nn */
                      if (ModRM(pat)) return;
                      /* Byte immediate value follows ModRM */
                      pc++;
                      continue;
                  case 0xC7:          /* Mov ModRM, #nnnn */
                      if (ModRM(pat)) return;
                      /* Word immediate value follows ModRM */
                      /* Immediate 16 bit values might be constant, but also
                          might be relocatable. For now, make them wild */
                      if (TwoWild(pat)) return;
                      continue;
  
                  case 0xC8:          /* Enter Iw, Ib */
                      pc += 3;        /* Constant word, byte */
                      continue;
                  case 0xC9:          /* Leave */
                      continue;
  
                  case 0xCC:          /* Int 3 */
                      continue;
  
                  case 0xCD:          /* Int nn */
                      intArg = pat[pc++];
                      if ((intArg >= 0x34) && (intArg <= 0x3B))
                      {
                          /* Borland/Microsoft FP emulations */
                          if (ModRM(pat)) return;
                      }
                      continue;
  
                  case 0xCE:          /* Into */
                      continue;
  
                  case 0xCF:          /* Iret */
                      continue;
  
                  case 0xD0:          /* Group 2 rotate, byte, 1 bit */
                  case 0xD1:          /* Group 2 rotate, word, 1 bit */
                  case 0xD2:          /* Group 2 rotate, byte, CL bits */
                  case 0xD3:          /* Group 2 rotate, word, CL bits */
                      if (ModRM(pat)) return;
                      continue;
  
                  case 0xD4:          /* Aam */
                  case 0xD5:          /* Aad */
                  case 0xD7:          /* Xlat */
                      continue;
  
                  case 0xD8:
                  case 0xD9:
                  case 0xDA:
                  case 0xDB:          /* Esc opcodes */
                  case 0xDC:          /* i.e. floating point */
                  case 0xDD:          /* coprocessor calls */
                  case 0xDE:
                  case 0xDF:
                      if (ModRM(pat)) return;
                      continue;
  
                  case 0xE0:          /* Loopne */
                  case 0xE1:          /* Loope */
                  case 0xE2:          /* Loop */
                  case 0xE3:          /* Jcxz */
                      pc++;           /* Short jump offset */
                      continue;
  
                  case 0xE4:          /* in  al,nn */
                  case 0xE6:          /* out nn,al */
                      pc++;
                      continue;
  
                  case 0xE5:          /* in ax,nn */
                  case 0xE7:          /* in nn,ax */
                      pc += 2;
                      continue;
  
                  case 0xE8:          /* Call rel */
                      if (TwoWild(pat)) return;
                      continue;
                  case 0xE9:          /* Jump rel, unconditional */
                      if (TwoWild(pat)) return;
                      chop(pat);
                      return;
                  case 0xEA:          /* Jump abs */
                      if (FourWild(pat)) return;
                      chop(pat);
                      return;
                  case 0xEB:          /* Jmp short unconditional */
                      pc++;
                      chop(pat);
                      return;
  
                  case 0xEC:          /* In  al,dx */
                  case 0xED:          /* In  ax,dx */
                  case 0xEE:          /* Out dx,al */
                  case 0xEF:          /* Out dx,ax */
                      continue;
  
                  case 0xF0:          /* Lock */
                  case 0xF2:          /* Repne */
                  case 0xF3:          /* Rep/repe */
                  case 0xF4:          /* Halt */
                  case 0xF5:          /* Cmc */
  
gt:                 case 0xF8:          /* Clc */