/* BEGIN_LEGAL Copyright (c) 2023 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. END_LEGAL */ /// This is the place to start learning about the decoder APIs. It /// exercises most of the essential features of the decoder. #include "xed/xed-interface.h" #include "xed-examples-util.h" #include #include #include #include int main(int argc, char** argv); #if defined(XED_APX) xed_reg_enum_t get_dfv_reg(const xed_decoded_inst_t* xedd){ /* returns default flag values reg if a decoded instruction uses DFV and INVALID reg otherwise.*/ const xed_inst_t* inst = xedd->_inst; const unsigned int noperands = xed_inst_noperands(inst); unsigned int i; for( i=0;i= XED_REG_DFV0 && r <= XED_REG_DFV15) { return r; } } return XED_REG_INVALID; } #endif void print_misc(xed_decoded_inst_t* xedd) { xed_uint_t i=0, j=0; const xed_operand_values_t* ov = xed_decoded_inst_operands_const(xedd); const xed_inst_t* xi = xed_decoded_inst_inst(xedd); xed_exception_enum_t e = xed_inst_exception(xi); xed_uint_t np = xed_decoded_inst_get_nprefixes(xedd); xed_isa_set_enum_t isaset = xed_decoded_inst_get_isa_set(xedd); if (xed_operand_values_has_real_rep(ov)) { xed_iclass_enum_t norep = xed_rep_remove(xed_decoded_inst_get_iclass(xedd)); printf("REAL REP "); printf("\tcorresponding no-rep iclass: %s\n" , xed_iclass_enum_t2str(norep)); } if (xed_operand_values_has_rep_prefix(ov)) { printf("F3 PREFIX\n"); } if (xed_operand_values_has_repne_prefix(ov)) { printf("F2 PREFIX\n"); } if (xed_operand_values_has_address_size_prefix(ov)) { printf("67 PREFIX\n"); } if (xed_operand_values_has_operand_size_prefix(ov)) { /* this 66 prefix is not part of the opcode */ printf("66-OSZ PREFIX\n"); } if (xed_operand_values_mandatory_66_prefix(ov)) { /* this 66 prefix is mandatory */ printf("MANDATORY 66 PREFIX\n"); } else if (xed_operand_values_has_66_prefix(ov)) { /* this is any 66 prefix including the above */ printf("ANY 66 PREFIX\n"); } if (xed3_operand_get_rex2(xedd)) { /* Legacy instructions with REX2 prefix have no new iforms. This function returns a non-zero number if REX2 prefix is detected for a Legacy instruction */ printf("REX2 PREFIX\n"); } if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_RING0)) { printf("RING0 only\n"); } if (e != XED_EXCEPTION_INVALID) { printf("EXCEPTION TYPE: %s\n", xed_exception_enum_t2str(e)); } if (xed_decoded_inst_is_broadcast(xedd)) printf("BROADCAST\n"); #if defined(XED_APX) if (xed_classify_apx(xedd)) { printf("[APX] "); if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_APX_NDD)) { printf("New-Data-Destination "); } if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_APX_NF)) { printf("No-Flags "); } if (xed3_operand_get_has_egpr(xedd)) { /* returns a non-zero number if one of the register/memory-structure operands of a decoded instruction is an extended GPR(EGPR) (valid for both Legacy and EVEX instructions) */ printf("Uses-EGPR "); } if (xed_decoded_inst_is_apx_zu(xedd)) { printf("Zero-Upper "); } printf("\n"); } #endif if (xed_classify_sse(xedd) || xed_classify_avx(xedd) || xed_classify_avx512(xedd) || xed_classify_amx(xedd)) { if (xed_classify_amx(xedd)) printf("AMX\n"); else if (xed_classify_avx512_maskop(xedd)) printf("AVX512 KMASK-OP\n"); else { xed_bool_t sse = 0; if (xed_classify_sse(xedd)) { sse = 1; printf("SSE\n"); } else if (xed_classify_avx(xedd)) printf("AVX\n"); else if (xed_classify_avx512(xedd)) printf("AVX512\n"); if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_SIMD_SCALAR)) printf("SCALAR\n"); else { // xed_decoded_inst_vector_length_bits is only for VEX/EVEX instr. // This will print 128 vl for FXSAVE and LD/ST MXCSR which is unfortunate. xed_uint_t vl_bits = sse ? 128 : xed_decoded_inst_vector_length_bits(xedd); printf("Vector length: %u\n", vl_bits); } if (xed_classify_avx512(xedd)) { xed_uint_t vec_elements = xed_decoded_inst_avx512_dest_elements(xedd); printf( "AVX512 vector elements: %u\n", vec_elements); } } } // does not include instructions that have XED_ATTRIBUTE_MASK_AS_CONTROL. // does not include vetor instructions that have k0 as a mask register. if (xed_decoded_inst_masked_vector_operation(xedd)) printf("WRITE-MASKING\n"); if (np) printf("Number of legacy prefixes: %u \n", np); printf("ISA SET: [%s]\n", xed_isa_set_enum_t2str(isaset)); for(i=0; i0 && t<5) printf("rounding mode override = %s\n", rounding_modes[t]); } } void print_branch_hints(xed_decoded_inst_t* xedd) { if (xed_operand_values_branch_not_taken_hint(xedd)) printf("HINT: NOT TAKEN\n"); else if (xed_operand_values_branch_taken_hint(xedd)) printf("HINT: TAKEN\n"); else if (xed_operand_values_cet_no_track(xedd)) printf("CET NO-TRACK\n"); } void print_attributes(xed_decoded_inst_t* xedd) { /* Walk the attributes. Generally, you'll know the one you want to * query and just access that one directly. */ const xed_inst_t* xi = xed_decoded_inst_inst(xedd); unsigned int i, nattributes = xed_attribute_max(); printf("ATTRIBUTES: "); for(i=0;is.zf) { printf("READS ZF\n"); } } } void print_flags(xed_decoded_inst_t* xedd) { unsigned int i, nflags; if (xed_decoded_inst_uses_rflags(xedd)) { const xed_simple_flag_t* rfi = xed_decoded_inst_get_rflags_info(xedd); assert(rfi); printf("FLAGS:\n"); if (xed_simple_flag_reads_flags(rfi)) { printf(" reads-rflags "); } else if (xed_simple_flag_writes_flags(rfi)) { //XED provides may-write and must-write information if (xed_simple_flag_get_may_write(rfi)) { printf(" may-write-rflags "); } if (xed_simple_flag_get_must_write(rfi)) { printf(" must-write-rflags "); } } nflags = xed_simple_flag_get_nflags(rfi); for( i=0;i> 3) & 0x1, (dfv_idx >> 2) & 0x1, (dfv_idx >> 1) & 0x1, (dfv_idx >> 0) & 0x1); } #endif } } void print_memops(xed_decoded_inst_t* xedd) { unsigned int i, memops = xed_decoded_inst_number_of_memory_operands(xedd); printf("Memory Operands\n"); for( i=0;i> 3); printf(" %2u", xed_decoded_inst_operand_elements(xedd,i)); printf(" %3u", xed_decoded_inst_operand_element_size_bits(xedd,i)); printf(" %10s", xed_operand_element_type_enum_t2str( xed_decoded_inst_operand_element_type(xedd,i))); printf(" %10s\n", xed_reg_class_enum_t2str( xed_reg_class( xed_decoded_inst_get_reg(xedd, op_name)))); } } int main(int argc, char** argv) { xed_state_t dstate; xed_decoded_inst_t xedd; xed_uint_t i, bytes = 0; xed_uint_t argcu = (xed_uint_t)argc; unsigned char itext[XED_MAX_INSTRUCTION_BYTES]; xed_uint_t first_argv; xed_bool_t already_set_mode = 0; xed_chip_enum_t chip = XED_CHIP_INVALID; char const* decode_text=0; unsigned int len; xed_error_enum_t xed_error; xed_uint_t operands_index = 0; xed_operand_enum_t operands[XED_MAX_INPUT_OPERNADS] = {XED_OPERAND_INVALID}; xed_uint32_t operands_value[XED_MAX_INPUT_OPERNADS] = {0}; #if defined(XED_MPX) unsigned int mpx_mode=0; #endif #if defined(XED_CET) unsigned int cet_mode=0; #endif xed_tables_init(); xed_state_zero(&dstate); first_argv = 1; dstate.mmode=XED_MACHINE_MODE_LEGACY_32; dstate.stack_addr_width=XED_ADDRESS_WIDTH_32b; for(i=1;i< argcu;i++) { if (strcmp(argv[i], "-64") == 0) { assert(already_set_mode == 0); already_set_mode = 1; dstate.mmode=XED_MACHINE_MODE_LONG_64; first_argv++; } #if defined(XED_MPX) else if (strcmp(argv[i], "-mpx") == 0) { mpx_mode = 1; first_argv++; } #endif #if defined(XED_CET) else if (strcmp(argv[i], "-cet") == 0) { cet_mode = 1; first_argv++; } #endif else if (strcmp(argv[i], "-16") == 0) { assert(already_set_mode == 0); already_set_mode = 1; dstate.mmode=XED_MACHINE_MODE_LEGACY_16; dstate.stack_addr_width=XED_ADDRESS_WIDTH_16b; first_argv++; } else if (strcmp(argv[i], "-s16") == 0) { already_set_mode = 1; dstate.stack_addr_width=XED_ADDRESS_WIDTH_16b; first_argv++; } else if (strcmp(argv[i], "-chip") == 0) { assert(i+1 < argcu); chip = str2xed_chip_enum_t(argv[i+1]); printf("Setting chip to %s\n", xed_chip_enum_t2str(chip)); assert(chip != XED_CHIP_INVALID); first_argv+=2; } else if (strcmp(argv[i], "-set") == 0) { assert(i+2 < argcu); // needs 2 args if (operands_index >= XED_MAX_INPUT_OPERNADS) { printf("ERROR: too many -set operands, max is %d\n", XED_MAX_INPUT_OPERNADS); exit(1); } operands[operands_index] = str2xed_operand_enum_t(argv[i+1]); if (operands[operands_index] == XED_OPERAND_INVALID){ printf("ERROR: operand %s doesn't exist\n", argv[i+1]); exit(1); } operands_value[operands_index] = XED_STATIC_CAST(xed_uint8_t, xed_atoi_general(argv[i+2],1000)); operands_index++; first_argv+=3; } } assert(first_argv < argcu); xed_decoded_inst_zero_set_mode(&xedd, &dstate); xed_decoded_inst_set_input_chip(&xedd, chip); #if defined(XED_MPX) xed3_operand_set_mpxmode(&xedd, mpx_mode); #endif #if defined(XED_CET) xed3_operand_set_cet(&xedd, cet_mode); #endif // set the value of operands referenced after '-set' for (i = 0; i < operands_index; i++) xed3_set_generic_operand(&xedd, operands[i], operands_value[i]); // convert ascii hex to hex bytes for(i=first_argv; i< argcu;i++) decode_text = xedex_append_string(decode_text,argv[i]); len = (unsigned int) strlen(decode_text); if ((len & 1) == 1) { printf("Must supply even number of nibbles per substring\n"); exit(1); } if (len > XED_MAX_INSTRUCTION_BYTES*2) { printf("Must supply at most 30 nibbles (15 bytes)\n"); exit(1); } bytes = xed_convert_ascii_to_hex(decode_text, itext, XED_MAX_INSTRUCTION_BYTES); if (bytes == 0) { printf("Must supply some hex bytes\n"); exit(1); } printf("Attempting to decode: "); for(i=0;i