// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* * Several simple types used by the disassembler and some of the patching * mechanisms. */ #ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H__ #define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H__ namespace sidestep { // Categories of instructions that we care about enum InstructionType { // This opcode is not used IT_UNUSED, // This disassembler does not recognize this opcode (error) IT_UNKNOWN, // This is not an instruction but a reference to another table IT_REFERENCE, // This byte is a prefix byte that we can ignore IT_PREFIX, // This is a prefix byte that switches to the nondefault address size IT_PREFIX_ADDRESS, // This is a prefix byte that switches to the nondefault operand size IT_PREFIX_OPERAND, // A jump or call instruction IT_JUMP, // A return instruction IT_RETURN, // Any other type of instruction (in this case we don't care what it is) IT_GENERIC, }; // Lists IA-32 operand sizes in multiples of 8 bits enum OperandSize { OS_ZERO = 0, OS_BYTE = 1, OS_WORD = 2, OS_DOUBLE_WORD = 4, OS_QUAD_WORD = 8, OS_DOUBLE_QUAD_WORD = 16, OS_32_BIT_POINTER = 32/8, OS_48_BIT_POINTER = 48/8, OS_SINGLE_PRECISION_FLOATING = 32/8, OS_DOUBLE_PRECISION_FLOATING = 64/8, OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8, OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8, OS_PSEUDO_DESCRIPTOR = 6 }; // Operand addressing methods from the IA-32 manual. The enAmMask value // is a mask for the rest. The other enumeration values are named for the // names given to the addressing methods in the manual, e.g. enAm_D is for // the D addressing method. // // The reason we use a full 4 bytes and a mask, is that we need to combine // these flags with the enOperandType to store the details // on the operand in a single integer. enum AddressingMethod { AM_NOT_USED = 0, // This operand is not used for this instruction AM_MASK = 0x00FF0000, // Mask for the rest of the values in this enumeration AM_A = 0x00010000, // A addressing type AM_C = 0x00020000, // C addressing type AM_D = 0x00030000, // D addressing type AM_E = 0x00040000, // E addressing type AM_F = 0x00050000, // F addressing type AM_G = 0x00060000, // G addressing type AM_I = 0x00070000, // I addressing type AM_J = 0x00080000, // J addressing type AM_M = 0x00090000, // M addressing type AM_O = 0x000A0000, // O addressing type AM_P = 0x000B0000, // P addressing type AM_Q = 0x000C0000, // Q addressing type AM_R = 0x000D0000, // R addressing type AM_S = 0x000E0000, // S addressing type AM_T = 0x000F0000, // T addressing type AM_V = 0x00100000, // V addressing type AM_W = 0x00110000, // W addressing type AM_X = 0x00120000, // X addressing type AM_Y = 0x00130000, // Y addressing type AM_REGISTER = 0x00140000, // Specific register is always used as this op AM_IMPLICIT = 0x00150000, // An implicit, fixed value is used }; // Operand types from the IA-32 manual. The enOtMask value is // a mask for the rest. The rest of the values are named for the // names given to these operand types in the manual, e.g. enOt_ps // is for the ps operand type in the manual. // // The reason we use a full 4 bytes and a mask, is that we need // to combine these flags with the enAddressingMethod to store the details // on the operand in a single integer. enum OperandType { OT_MASK = 0xFF000000, OT_A = 0x01000000, OT_B = 0x02000000, OT_C = 0x03000000, OT_D = 0x04000000, OT_DQ = 0x05000000, OT_P = 0x06000000, OT_PI = 0x07000000, OT_PS = 0x08000000, // actually unsupported for (we don't know its size) OT_Q = 0x09000000, OT_S = 0x0A000000, OT_SS = 0x0B000000, OT_SI = 0x0C000000, OT_V = 0x0D000000, OT_W = 0x0E000000, OT_SD = 0x0F000000, // scalar double-precision floating-point value OT_PD = 0x10000000, // double-precision floating point // dummy "operand type" for address mode M - which doesn't specify // operand type OT_ADDRESS_MODE_M = 0x80000000 }; // Everything that's in an Opcode (see below) except the three // alternative opcode structs for different prefixes. struct SpecificOpcode { // Index to continuation table, or 0 if this is the last // byte in the opcode. int table_index_; // The opcode type InstructionType type_; // Description of the type of the dest, src and aux operands, // put together from an enOperandType flag and an enAddressingMethod // flag. int flag_dest_; int flag_source_; int flag_aux_; // We indicate the mnemonic for debugging purposes const char* mnemonic_; }; // The information we keep in our tables about each of the different // valid instructions recognized by the IA-32 architecture. struct Opcode { // Index to continuation table, or 0 if this is the last // byte in the opcode. int table_index_; // The opcode type InstructionType type_; // Description of the type of the dest, src and aux operands, // put together from an enOperandType flag and an enAddressingMethod // flag. int flag_dest_; int flag_source_; int flag_aux_; // We indicate the mnemonic for debugging purposes const char* mnemonic_; // Alternative opcode info if certain prefixes are specified. // In most cases, all of these are zeroed-out. Only used if // bPrefixDependent is true. bool is_prefix_dependent_; SpecificOpcode opcode_if_f2_prefix_; SpecificOpcode opcode_if_f3_prefix_; SpecificOpcode opcode_if_66_prefix_; }; // Information about each table entry. struct OpcodeTable { // Table of instruction entries const Opcode* table_; // How many bytes left to shift ModR/M byte before applying mask unsigned char shift_; // Mask to apply to byte being looked at before comparing to table unsigned char mask_; // Minimum/maximum indexes in table. unsigned char min_lim_; unsigned char max_lim_; }; // Information about each entry in table used to decode ModR/M byte. struct ModrmEntry { // Is the operand encoded as bytes in the instruction (rather than // if it's e.g. a register in which case it's just encoded in the // ModR/M byte) bool is_encoded_in_instruction_; // Is there a SIB byte? In this case we always need to decode it. bool use_sib_byte_; // What is the size of the operand (only important if it's encoded // in the instruction)? OperandSize operand_size_; }; }; // namespace sidestep #endif // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H__