Exemple #1
0
/*
 * decode_ext()
 *
 *    Decode opcode extensions (if any)
 */
static int
decode_ext(struct ud *u, uint16_t ptr)
{
  uint8_t idx = 0;
  if ((ptr & 0x8000) == 0) {
    return decode_insn(u, ptr); 
  }
  u->le = &ud_lookup_table_list[(~0x8000 & ptr)];
  if (u->le->type == UD_TAB__OPC_3DNOW) {
    return decode_3dnow(u);
  }

  switch (u->le->type) {
    case UD_TAB__OPC_MOD:
      /* !11 = 0, 11 = 1 */
      idx = (MODRM_MOD(modrm(u)) + 1) / 4;
      break;
      /* disassembly mode/operand size/address size based tables.
       * 16 = 0,, 32 = 1, 64 = 2
       */
    case UD_TAB__OPC_MODE:
      idx = u->dis_mode / 32;
      break;
    case UD_TAB__OPC_OSIZE:
      idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32;
      break;
    case UD_TAB__OPC_ASIZE:
      idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32;
      break;
    case UD_TAB__OPC_X87:
      idx = modrm(u) - 0xC0;
      break;
    case UD_TAB__OPC_VENDOR:
      if (u->vendor == UD_VENDOR_ANY) {
        /* choose a valid entry */
        idx = (u->le->table[idx] != 0) ? 0 : 1;
      } else if (u->vendor == UD_VENDOR_AMD) {
        idx = 0;
      } else {
        idx = 1;
      }
      break;
    case UD_TAB__OPC_RM:
      idx = MODRM_RM(modrm(u));
      break;
    case UD_TAB__OPC_REG:
      idx = MODRM_REG(modrm(u));
      break;
    case UD_TAB__OPC_SSE:
      return decode_ssepfx(u);
    default:
      assert(!"not reached");
      break;
  }

  return decode_ext(u, u->le->table[idx]);
}
Exemple #2
0
int32_t emu_cpu_parse(struct emu_cpu *c)
{
	if (c->repeat_current_instr == true)
	{
		return 0;
	}

	/* TODO make unstatic for threadsafety */
	uint8_t byte;
	uint8_t *opcode;
	uint32_t ret;
	
	c->instr.prefixes = 0;
	
	
//	logDebug(c->emu,"decoding\n");
//	emu_cpu_debug_print(c);

	uint8_t dis[32];
	uint32_t readOk = emu_memory_read_block(c->mem,c->eip,dis,32);

	if(readOk != 0){ //dzzie 5.14.11
		emu_strerror_set(c->emu,"emu_parse no memory found at 0x%x\n", c->eip);
		emu_errno_set(c->emu, EOPNOTSUPP);
		return -1;
	}

	uint32_t expected_instr_size = 0;
	if( CPU_DEBUG_FLAG_ISSET(c, instruction_string ) || CPU_DEBUG_FLAG_ISSET(c, instruction_size ) )
	{
		expected_instr_size = dasm_print_instruction(c->eip,dis,0,c->instr_string);
	}

	uint32_t eip_before = c->eip;
	uint32_t eip_after = 0;


	/* reset the instruction source and track infos, maybe move to a fn and call the fn instead? */

	c->instr.source.has_cond_pos = 0;

	/*c->instr.track.init.eflags = 0;
	memset(c->instr.track.init.reg, 0, sizeof(uint32_t) * 8);
	c->instr.track.init.fpu = 0;

	c->instr.track.need.eflags = 0;
	memset(c->instr.track.need.reg, 0, sizeof(uint32_t) * 8);
	c->instr.track.need.fpu = 0;
	*/

	while( 1 )
	{
		ret = emu_memory_read_byte(c->mem, c->eip++, &byte);
		
		if( ret != 0 )
			return ret;
		
		c->cpu_instr_info = &ii_onebyte[byte];
	
		if( c->cpu_instr_info->function == prefix_fn )
		{
			c->instr.prefixes |= prefix_map[byte];
			continue;
		}
		else
		{
			c->instr.opc = byte;
			if( c->cpu_instr_info->format.fpu_info == 0 )
			{
				c->instr.is_fpu = 0;
				c->instr.cpu.opc = c->instr.opc;
				c->instr.cpu.prefixes = c->instr.prefixes;
				
				if( c->instr.cpu.opc == 0x0f )
				{
					ret = emu_memory_read_byte(c->mem, c->eip++, &byte);
			
					if( ret != 0 )
						return ret;
						
					c->instr.cpu.opc_2nd = byte;
					opcode = &c->instr.cpu.opc_2nd;
					c->cpu_instr_info = &ii_twobyte[byte];
				}
				else
				{
					opcode = &c->instr.cpu.opc;
				}
				
				if ( c->cpu_instr_info->function == 0 )
				{
					if( c->instr.cpu.opc == 0x0f )
						emu_strerror_set(c->emu,"opcode 0f %02x not supported\n", c->instr.cpu.opc_2nd);
					else
						emu_strerror_set(c->emu,"opcode %02x not supported\n", c->instr.cpu.opc);

					emu_errno_set(c->emu, EOPNOTSUPP);
/*					int y=0;
					for (y=0;y<expected_instr_size;y++)
					{
						printf("%02x ", dis[y]);
					}
					printf("\n");
*/
					return -1;
				}
				
				c->instr.cpu.w_bit = *opcode & 1;
				c->instr.cpu.s_bit = (*opcode >> 1) & 1;
	
				/* mod r/m byte?  sib/disp */
				if( c->cpu_instr_info->format.modrm_byte != 0 )
				{
					ret = emu_memory_read_byte(c->mem, c->eip++, &byte);
			
					if( ret != 0 )
						return ret;
						
					c->instr.cpu.modrm.mod = MODRM_MOD(byte);
					c->instr.cpu.modrm.opc = MODRM_REGOPC(byte);
					c->instr.cpu.modrm.rm = MODRM_RM(byte);
					
					if( c->cpu_instr_info->format.modrm_byte == II_MOD_REG_RM || c->cpu_instr_info->format.modrm_byte == II_MOD_YYY_RM ||
						c->cpu_instr_info->format.modrm_byte == II_XX_REG1_REG2) /* cases with possible sib/disp*/
					{
						if( c->instr.cpu.modrm.mod != 3 )
						{
							if( c->instr.cpu.modrm.rm != 4 && !(c->instr.cpu.modrm.mod == 0 && c->instr.cpu.modrm.rm == 5) )
							{
                                c->instr.cpu.modrm.ea = c->reg[c->instr.cpu.modrm.rm];
								//TRACK_NEED_REG32(c->instr, c->instr.cpu.modrm.rm);
							}
							else
								c->instr.cpu.modrm.ea = 0;
							
							if( c->instr.cpu.modrm.rm == 4 ) /* sib byte present */
							{
								ret = emu_memory_read_byte(c->mem, c->eip++, &byte);
			
								if( ret != 0 )
									return ret;
									
								c->instr.cpu.modrm.sib.base = SIB_BASE(byte);
								c->instr.cpu.modrm.sib.scale = SIB_SCALE(byte);
								c->instr.cpu.modrm.sib.index = SIB_INDEX(byte);
								
								if( c->instr.cpu.modrm.sib.base != 5 )
								{
									c->instr.cpu.modrm.ea += c->reg[c->instr.cpu.modrm.sib.base];
									//TRACK_NEED_REG32(c->instr, c->instr.cpu.modrm.sib.base);
								}
								else if( c->instr.cpu.modrm.mod != 0 )
								{
									c->instr.cpu.modrm.ea += c->reg[ebp];
									//TRACK_NEED_REG32(c->instr, ebp);
								}
	
								if( c->instr.cpu.modrm.sib.index != 4 )
								{
									c->instr.cpu.modrm.ea += c->reg[c->instr.cpu.modrm.sib.index] * scalem[c->instr.cpu.modrm.sib.scale];
									//TRACK_NEED_REG32(c->instr, c->instr.cpu.modrm.sib.index);
								}
							}
							
							if( c->instr.cpu.modrm.mod == 1 ) /* disp8 */
							{
								ret = emu_memory_read_byte(c->mem, c->eip++, &c->instr.cpu.modrm.disp.s8);
			
								if( ret != 0 )
									return ret;
								
								c->instr.cpu.modrm.ea += (int8_t)c->instr.cpu.modrm.disp.s8;
							}
							else if( c->instr.cpu.modrm.mod == 2 || (c->instr.cpu.modrm.mod == 0 && c->instr.cpu.modrm.rm == 5) ) /* disp32 */
							{
								ret = emu_memory_read_dword(c->mem, c->eip, &c->instr.cpu.modrm.disp.s32);
								c->eip += 4;
			
								if( ret != 0 )
									return ret;
	
								c->instr.cpu.modrm.ea += c->instr.cpu.modrm.disp.s32;
							}
						}
					}
				}
				
				/* */
				c->instr.cpu.operand_size = 0;
				
				if( c->cpu_instr_info->format.imm_data == II_IMM8 || c->cpu_instr_info->format.disp_data == II_DISP8 )
					c->instr.cpu.operand_size = OPSIZE_8;
				else if( c->cpu_instr_info->format.imm_data == II_IMM16 || c->cpu_instr_info->format.disp_data == II_DISP16 )
					c->instr.cpu.operand_size = OPSIZE_16;
				else if( c->cpu_instr_info->format.imm_data == II_IMM32 || c->cpu_instr_info->format.disp_data == II_DISP32 )
					c->instr.cpu.operand_size = OPSIZE_32;
				else if( c->cpu_instr_info->format.imm_data == II_IMM || c->cpu_instr_info->format.disp_data == II_DISPF
					 || (c->cpu_instr_info->format.type && !c->instr.cpu.modrm.opc))
				{
					if( c->cpu_instr_info->format.w_bit == 1 && c->instr.cpu.w_bit == 0 )
						c->instr.cpu.operand_size = OPSIZE_8;
					else
					{
						if( c->instr.cpu.prefixes & PREFIX_OPSIZE )
							c->instr.cpu.operand_size = OPSIZE_16;
						else
							c->instr.cpu.operand_size = OPSIZE_32;
					}
				}
				
				/* imm */
				if( c->cpu_instr_info->format.imm_data != 0 || (c->cpu_instr_info->format.type && !c->instr.cpu.modrm.opc))
				{
					if( c->instr.cpu.operand_size == OPSIZE_32 )
					{
						ret = emu_memory_read_dword(c->mem, c->eip, &c->instr.cpu.imm);
						c->eip += 4;
					}
					else if( c->instr.cpu.operand_size == OPSIZE_8 )
					{
						ret = emu_memory_read_byte(c->mem, c->eip++, c->instr.cpu.imm8);
					}
					else if( c->instr.cpu.operand_size == OPSIZE_16 )
					{
						ret = emu_memory_read_word(c->mem, c->eip, c->instr.cpu.imm16);
						c->eip += 2;
					}
	
					if( ret != 0 )
						return ret;
				}
				
				/* disp */
				if( c->cpu_instr_info->format.disp_data != 0 )
				{
					if( c->instr.cpu.operand_size == OPSIZE_32 )
					{
						uint32_t disp32;
						ret = emu_memory_read_dword(c->mem, c->eip, &disp32);
						c->instr.cpu.disp = (int32_t)disp32;
						c->eip += 4;
					}
					else if( c->instr.cpu.operand_size == OPSIZE_16 )
					{
						uint16_t disp16;
						ret = emu_memory_read_word(c->mem, c->eip, &disp16);
						c->instr.cpu.disp = (int16_t)disp16;
						c->eip += 2;
					}
					else if( c->instr.cpu.operand_size == OPSIZE_8 )
					{
						uint8_t disp8;
						ret = emu_memory_read_byte(c->mem, c->eip++, &disp8);
						c->instr.cpu.disp = (int8_t)disp8;
					}
	
					if( ret != 0 )
						return ret;
				}
				
				/* TODO level type ... */
			}
			else /* fpu */
			{
				/* this is a minimal parser without exact decomposition
				 * into all fields. instead it determines the length of
				 * the instruction and ignores pretty much everything else
				 * except for a few explicitly implemented instructions. */
				c->instr.is_fpu = 1;
				c->instr.fpu.prefixes = c->instr.prefixes;

				c->instr.fpu.fpu_data[0] = c->instr.opc;

				ret = emu_memory_read_byte(c->mem, c->eip++, &c->instr.fpu.fpu_data[1]);
				if( ret != 0 )
					return ret;
				
				if( FPU_MOD(c->instr.fpu.fpu_data) != 3 ) /* intel pdf page 36 */
				{
					/* trivial case, one register is ea */
		   			if( FPU_RM(c->instr.fpu.fpu_data) != 4 && !(FPU_MOD(c->instr.fpu.fpu_data) == 0 && FPU_RM(c->instr.fpu.fpu_data) == 5) )
						c->instr.fpu.ea = c->reg[FPU_RM(c->instr.fpu.fpu_data)];
					else
						c->instr.fpu.ea = 0;
					
					/* sib byte */
					if( FPU_RM(c->instr.fpu.fpu_data) == 4 )
					{
						ret = emu_memory_read_byte(c->mem, c->eip++, &byte);
			
						if( ret != 0 )
							return ret;
						
						if( SIB_BASE(byte) != 5 )
						{
							c->instr.fpu.ea += c->reg[SIB_BASE(byte)];
						}
						else if( FPU_MOD(c->instr.fpu.fpu_data) != 0 )
						{
							c->instr.fpu.ea += c->reg[ebp];
						}

						if( SIB_INDEX(byte) != 4 )
						{
							c->instr.fpu.ea += c->reg[SIB_INDEX(byte)] * scalem[SIB_SCALE(byte)];
						}
					}
					
					/* modrm */
					if( FPU_MOD(c->instr.fpu.fpu_data) == 1 )
					{
						ret = emu_memory_read_byte(c->mem, c->eip++, &byte);

						if( ret != 0 )
							return ret;
						
						c->instr.fpu.ea += (int8_t)byte;
					}
					else if( FPU_MOD(c->instr.fpu.fpu_data) == 2 || (FPU_MOD(c->instr.fpu.fpu_data) == 0 && FPU_RM(c->instr.fpu.fpu_data) == 5) ) 
					{
						uint32_t dword;
						ret = emu_memory_read_dword(c->mem, c->eip, &dword);
						c->eip += 4;

						if( ret != 0 )
							return ret;

						c->instr.fpu.ea += dword;
					}
				}
				
				/*c->instr.fpu.last_instr = c->last_fpu_instr;*/
				
				
				c->last_fpu_instr[1] = c->last_fpu_instr[0]; 
				c->last_fpu_instr[0] = eip_before;
			}
			
//			logDebug(c->emu,"\n");

			eip_after = c->eip;
			if ( CPU_DEBUG_FLAG_ISSET(c, instruction_size ) && eip_after - eip_before != expected_instr_size)
			{
				logDebug(c->emu, "broken instr.cpu size %i %i\n",
				 	   eip_after - eip_before,
				 	   expected_instr_size);
				return -1;
			}


			/* the default normal position is behind the instruction, specific instructions as call jmp set their
			 * norm position 
			 */
			if ( c->instr.is_fpu == 0 )
			{
				SOURCE_NORM_POS(c->instr, c->eip);
			}
			else
			{
				SOURCE_NORM_POS(c->instr, c->eip);
			}


			break;
		}
Exemple #3
0
/*
 * decode_modrm_rm
 *
 *    Decodes rm field of mod/rm byte
 * 
 */
static void 
decode_modrm_rm(struct ud         *u, 
                struct ud_operand *op,
                unsigned char      type,
                unsigned int       size)

{
  unsigned char mod, rm, reg;

  /* get mod, r/m and reg fields */
  mod = MODRM_MOD(modrm(u));
  rm  = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u));
  reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u));

  op->size = resolve_operand_size(u, size);

  /* 
   * If mod is 11b, then the modrm.rm specifies a register.
   *
   */
  if (mod == 3) {
    op->type = UD_OP_REG;
    if (type ==  T_GPR) {
      op->base = decode_gpr(u, op->size, rm);
    } else {
      op->base = resolve_reg(u, type, (REX_B(u->pfx_rex) << 3) | (rm & 7));
    }
    return;
  } 


  /* 
   * !11 => Memory Address
   */  
  op->type = UD_OP_MEM;

  if (u->adr_mode == 64) {
    op->base = UD_R_RAX + rm;
    if (mod == 1) {
      op->offset = 8;
    } else if (mod == 2) {
      op->offset = 32;
    } else if (mod == 0 && (rm & 7) == 5) {           
      op->base = UD_R_RIP;
      op->offset = 32;
    } else {
      op->offset = 0;
    }
    /* 
     * Scale-Index-Base (SIB) 
     */
    if ((rm & 7) == 4) {
      inp_next(u);
      
      op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
      op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
      op->base  = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

      /* special conditions for base reference */
      if (op->index == UD_R_RSP) {
        op->index = UD_NONE;
        op->scale = UD_NONE;
      }

      if (op->base == UD_R_RBP || op->base == UD_R_R13) {
        if (mod == 0) {
          op->base = UD_NONE;
        } 
        if (mod == 1) {
          op->offset = 8;
        } else {
          op->offset = 32;
        }
      }
    }
  } else if (u->adr_mode == 32) {
    op->base = UD_R_EAX + rm;
    if (mod == 1) {
      op->offset = 8;
    } else if (mod == 2) {
      op->offset = 32;
    } else if (mod == 0 && rm == 5) {
      op->base = UD_NONE;
      op->offset = 32;
    } else {
      op->offset = 0;
    }

    /* Scale-Index-Base (SIB) */
    if ((rm & 7) == 4) {
      inp_next(u);

      op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
      op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
      op->base  = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

      if (op->index == UD_R_ESP) {
        op->index = UD_NONE;
        op->scale = UD_NONE;
      }

      /* special condition for base reference */
      if (op->base == UD_R_EBP) {
        if (mod == 0) {
          op->base = UD_NONE;
        } 
        if (mod == 1) {
          op->offset = 8;
        } else {
          op->offset = 32;
        }
      }
    }
  } else {
    const unsigned int bases[]   = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP,
                                     UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX };
    const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI,
                                     UD_NONE, UD_NONE, UD_NONE, UD_NONE };
    op->base  = bases[rm & 7];
    op->index = indices[rm & 7];
    if (mod == 0 && rm == 6) {
      op->offset= 16;
      op->base = UD_NONE;
    } else if (mod == 1) {
      op->offset = 8;
    } else if (mod == 2) { 
      op->offset = 16;
    }
  }

  /* 
   * extract offset, if any 
   */
  switch (op->offset) {
    case 8 : op->lval.ubyte  = inp_uint8(u);  break;
    case 16: op->lval.uword  = inp_uint16(u); break;
    case 32: op->lval.udword = inp_uint32(u); break;
    case 64: op->lval.uqword = inp_uint64(u); break;
    default: break;
  }
}
Exemple #4
0
/*
 * decode_modrm_rm
 *
 *    Decodes rm field of mod/rm byte
 * 
 */
static void 
decode_modrm_rm(struct ud         *u, 
                struct ud_operand *op,
                unsigned char      type,    /* register type */
                unsigned int       size)    /* operand size */

{
  size_t offset = 0;
  unsigned char mod, rm;

  /* get mod, r/m and reg fields */
  mod = MODRM_MOD(modrm(u));
  rm  = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u));

  /* 
   * If mod is 11b, then the modrm.rm specifies a register.
   *
   */
  if (mod == 3) {
    decode_reg(u, op, type, rm, size);
    return;
  }

  /* 
   * !11b => Memory Address
   */  
  op->type = UD_OP_MEM;
  op->size = resolve_operand_size(u, size);

  if (u->adr_mode == 64) {
    op->base = UD_R_RAX + rm;
    if (mod == 1) {
      offset = 8;
    } else if (mod == 2) {
      offset = 32;
    } else if (mod == 0 && (rm & 7) == 5) {           
      op->base = UD_R_RIP;
      offset = 32;
    } else {
      offset = 0;
    }
    /* 
     * Scale-Index-Base (SIB) 
     */
    if ((rm & 7) == 4) {
      inp_next(u);
      
      op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
      op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
      op->base  = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

      /* special conditions for base reference */
      if (op->index == UD_R_RSP) {
        op->index = UD_NONE;
        op->scale = UD_NONE;
      }

      if (op->base == UD_R_RBP || op->base == UD_R_R13) {
        if (mod == 0) {
          op->base = UD_NONE;
        } 
        if (mod == 1) {
          offset = 8;
        } else {
          offset = 32;
        }
      }
    }
  } else if (u->adr_mode == 32) {
    op->base = UD_R_EAX + rm;
    if (mod == 1) {
      offset = 8;
    } else if (mod == 2) {
      offset = 32;
    } else if (mod == 0 && rm == 5) {
      op->base = UD_NONE;
      offset = 32;
    } else {
      offset = 0;
    }

    /* Scale-Index-Base (SIB) */
    if ((rm & 7) == 4) {
      inp_next(u);

      op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
      op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
      op->base  = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

      if (op->index == UD_R_ESP) {
        op->index = UD_NONE;
        op->scale = UD_NONE;
      }

      /* special condition for base reference */
      if (op->base == UD_R_EBP) {
        if (mod == 0) {
          op->base = UD_NONE;
        } 
        if (mod == 1) {
          offset = 8;
        } else {
          offset = 32;
        }
      }
    }
  } else {
    const unsigned int bases[]   = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP,
                                     UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX };
    const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI,
                                     UD_NONE, UD_NONE, UD_NONE, UD_NONE };
    op->base  = bases[rm & 7];
    op->index = indices[rm & 7];
    if (mod == 0 && rm == 6) {
      offset = 16;
      op->base = UD_NONE;
    } else if (mod == 1) {
      offset = 8;
    } else if (mod == 2) { 
      offset = 16;
    }
  }

  if (offset) {
    decode_mem_disp(u, offset, op);
  }
}
Exemple #5
0
/* -----------------------------------------------------------------------------
 * decode_modrm() - Decodes ModRM Byte
 * -----------------------------------------------------------------------------
 */
static void 
decode_modrm(struct ud* u, struct ud_operand *op, unsigned int s, 
         unsigned char rm_type, struct ud_operand *opreg, 
			 unsigned int reg_size, unsigned char reg_type)
{
  unsigned char mod, rm, reg;

  inp_next(u);

  /* get mod, r/m and reg fields */
  mod = MODRM_MOD(inp_curr(u));
  rm  = (REX_B(u->pfx_rex) << 3) | MODRM_RM(inp_curr(u));
  reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(inp_curr(u));

  op->size = (uint8_t) resolve_operand_size(u, s);

  /* if mod is 11b, then the UD_R_m specifies a gpr/mmx/sse/control/debug */
  if (mod == 3) {
    op->type = UD_OP_REG;
    if (rm_type ==  T_GPR)
        op->base = decode_gpr(u, op->size, rm);
    else    op->base = resolve_reg(u, rm_type, (REX_B(u->pfx_rex) << 3) | (rm&7));
  } 
  /* else its memory addressing */  
  else {
    op->type = UD_OP_MEM;

    /* 64bit addressing */
    if (u->adr_mode == 64) {

        op->base = UD_R_RAX + rm;

        /* get offset type */
        if (mod == 1)
            op->offset = 8;
        else if (mod == 2)
            op->offset = 32;
        else if (mod == 0 && (rm & 7) == 5) {           
            op->base = UD_R_RIP;
            op->offset = 32;
        } else  op->offset = 0;

        /* Scale-Index-Base (SIB) */
        if ((rm & 7) == 4) {
            inp_next(u);
            
            op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
            op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
            op->base  = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

            /* special conditions for base reference */
            if (op->index == UD_R_RSP) {
                op->index = UD_NONE;
                op->scale = UD_NONE;
            }

            if (op->base == UD_R_RBP || op->base == UD_R_R13) {
                if (mod == 0) 
                    op->base = UD_NONE;
                if (mod == 1)
                    op->offset = 8;
                else op->offset = 32;
            }
        }
    } 

    /* 32-Bit addressing mode */
    else if (u->adr_mode == 32) {

        /* get base */
        op->base = UD_R_EAX + rm;

        /* get offset type */
        if (mod == 1)
            op->offset = 8;
        else if (mod == 2)
            op->offset = 32;
        else if (mod == 0 && rm == 5) {
            op->base = UD_NONE;
            op->offset = 32;
        } else  op->offset = 0;

        /* Scale-Index-Base (SIB) */
        if ((rm & 7) == 4) {
            inp_next(u);

            op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
            op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
            op->base  = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));

            if (op->index == UD_R_ESP) {
                op->index = UD_NONE;
                op->scale = UD_NONE;
            }

            /* special condition for base reference */
            if (op->base == UD_R_EBP) {
                if (mod == 0)
                    op->base = UD_NONE;
                if (mod == 1)
                    op->offset = 8;
                else op->offset = 32;
            }
        }
    } 

    /* 16bit addressing mode */
    else  {
        switch (rm) {
            case 0: op->base = UD_R_BX; op->index = UD_R_SI; break;
            case 1: op->base = UD_R_BX; op->index = UD_R_DI; break;
            case 2: op->base = UD_R_BP; op->index = UD_R_SI; break;
            case 3: op->base = UD_R_BP; op->index = UD_R_DI; break;
            case 4: op->base = UD_R_SI; break;
            case 5: op->base = UD_R_DI; break;
            case 6: op->base = UD_R_BP; break;
            case 7: op->base = UD_R_BX; break;
        }

        if (mod == 0 && rm == 6) {
            op->offset= 16;
            op->base = UD_NONE;
        }
        else if (mod == 1)
            op->offset = 8;
        else if (mod == 2) 
            op->offset = 16;
    }
  }  

  /* extract offset, if any */
  switch(op->offset) {
    case 8 : op->lval.ubyte  = inp_uint8(u);  break;
    case 16: op->lval.uword  = inp_uint16(u);  break;
    case 32: op->lval.udword = inp_uint32(u); break;
    default: break;
  }

  /* resolve register encoded in reg field */
  if (opreg) {
    opreg->type = UD_OP_REG;
    opreg->size = (uint8_t)resolve_operand_size(u, reg_size);
    if (reg_type == T_GPR) 
        opreg->base = decode_gpr(u, opreg->size, reg);
    else opreg->base = resolve_reg(u, reg_type, reg);
  }
}
Exemple #6
0
/* Searches the instruction tables for the right entry.
 */
static int search_itab( struct ud * u )
{
    struct ud_itab_entry * e = NULL;
    enum ud_itab_index table;
    uint8_t peek;
    uint8_t did_peek = 0;
    uint8_t curr; 
    uint8_t index;

    /* if in state of error, return */
    if ( u->error ) 
        return -1;

    /* get first byte of opcode. */
    inp_next(u); 
    if ( u->error ) 
        return -1;
    curr = inp_curr(u); 

    /* resolve xchg, nop, pause crazyness */
    if ( 0x90 == curr ) {
        if ( !( u->dis_mode == 64 && REX_B( u->pfx_rex ) ) ) {
            if ( u->pfx_rep ) {
                u->pfx_rep = 0;
                e = & ie_pause;
            } else {
                e = & ie_nop;
            }
            goto found_entry;
        }
    }

    /* get top-level table */
    if ( 0x0F == curr ) {
        table = ITAB__0F;
        curr  = inp_next(u);
        if ( u->error )
            return -1;

        /* 2byte opcodes can be modified by 0x66, F3, and F2 prefixes */
        if ( 0x66 == u->pfx_insn ) {
            if ( ud_itab_list[ ITAB__PFX_SSE66__0F ][ curr ].mnemonic != UD_Iinvalid ) {
                table = ITAB__PFX_SSE66__0F;
                u->pfx_opr = 0;
            }
        } else if ( 0xF2 == u->pfx_insn ) {
            if ( ud_itab_list[ ITAB__PFX_SSEF2__0F ][ curr ].mnemonic != UD_Iinvalid ) {
                table = ITAB__PFX_SSEF2__0F; 
                u->pfx_repne = 0;
            }
        } else if ( 0xF3 == u->pfx_insn ) {
            if ( ud_itab_list[ ITAB__PFX_SSEF3__0F ][ curr ].mnemonic != UD_Iinvalid ) {
                table = ITAB__PFX_SSEF3__0F;
                u->pfx_repe = 0;
                u->pfx_rep  = 0;
            }
        }
    /* pick an instruction from the 1byte table */
    } else {
        table = ITAB__1BYTE; 
    }

    index = curr;

search:

    e = & ud_itab_list[ table ][ index ];

    /* if mnemonic constant is a standard instruction constant
     * our search is over.
     */
    
    if ( e->mnemonic < UD_Id3vil ) {
        if ( e->mnemonic == UD_Iinvalid ) {
            if ( did_peek ) {
                inp_next( u ); if ( u->error ) return -1;
            }
            goto found_entry;
        }
        goto found_entry;
    }

    table = e->prefix;

    switch ( e->mnemonic )
    {
    case UD_Igrp_reg:
        peek     = inp_peek( u );
        did_peek = 1;
        index    = MODRM_REG( peek );
        break;

    case UD_Igrp_mod:
        peek     = inp_peek( u );
        did_peek = 1;
        index    = MODRM_MOD( peek );
        if ( index == 3 )
           index = ITAB__MOD_INDX__11;
        else 
           index = ITAB__MOD_INDX__NOT_11; 
        break;

    case UD_Igrp_rm:
        curr     = inp_next( u );
        did_peek = 0;
        if ( u->error )
            return -1;
        index    = MODRM_RM( curr );
        break;

    case UD_Igrp_x87:
        curr     = inp_next( u );
        did_peek = 0;
        if ( u->error )
            return -1;
        index    = curr - 0xC0;
        break;

    case UD_Igrp_osize:
        if ( u->opr_mode == 64 ) 
            index = ITAB__MODE_INDX__64;
        else if ( u->opr_mode == 32 ) 
            index = ITAB__MODE_INDX__32;
        else
            index = ITAB__MODE_INDX__16;
        break;
 
    case UD_Igrp_asize:
        if ( u->adr_mode == 64 ) 
            index = ITAB__MODE_INDX__64;
        else if ( u->adr_mode == 32 ) 
            index = ITAB__MODE_INDX__32;
        else
            index = ITAB__MODE_INDX__16;
        break;               

    case UD_Igrp_mode:
        if ( u->dis_mode == 64 ) 
            index = ITAB__MODE_INDX__64;
        else if ( u->dis_mode == 32 ) 
            index = ITAB__MODE_INDX__32;
        else
            index = ITAB__MODE_INDX__16;
        break;

    case UD_Igrp_vendor:
        if ( u->vendor == UD_VENDOR_INTEL ) 
            index = ITAB__VENDOR_INDX__INTEL; 
        else if ( u->vendor == UD_VENDOR_AMD )
            index = ITAB__VENDOR_INDX__AMD;
/*         else */
/*             assert( !"unrecognized vendor id" ); */
        break;

    case UD_Id3vil:
/*         assert( !"invalid instruction mnemonic constant Id3vil" ); */
        break;

    default:
/*         assert( !"invalid instruction mnemonic constant" ); */
        break;
    }

    goto search;

found_entry:

    u->itab_entry = e;
    u->mnemonic = u->itab_entry->mnemonic;

    return 0;
}