You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
9.0 KiB
318 lines
9.0 KiB
3 years ago
|
/* BEGIN_LEGAL
|
||
|
|
||
|
Copyright (c) 2021 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 */
|
||
|
/// @file xed-ex-agen.c
|
||
|
|
||
|
// decoder example with agen callbacks.
|
||
|
|
||
|
#include "xed/xed-interface.h"
|
||
|
#include "xed-examples-util.h"
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h> //strcmp
|
||
|
#include <assert.h>
|
||
|
|
||
|
int main(int argc, char** argv);
|
||
|
|
||
|
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
|
||
|
xed_uint64_t register_callback(xed_reg_enum_t reg, void* context, xed_bool_t* error) {
|
||
|
(void) context; // pacify compiler
|
||
|
(void) error;
|
||
|
|
||
|
/* After we register this function (see xed_agen_register_callback in
|
||
|
* main()), this function is called as needed by xed_agen(). This
|
||
|
* function provides register values for xed_agen(). In a real usage,
|
||
|
* you would probably pass in a context (in your call to xed_agen())
|
||
|
* that contains the actual values. */
|
||
|
|
||
|
|
||
|
/* Note that AL is required for the XLAT instruction. That is the only
|
||
|
byte reg needed. Also note, that for real mode, raw segement
|
||
|
selectors are returned by this function. */
|
||
|
|
||
|
/* in reality, you'd have to return valid values for each case */
|
||
|
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
|
||
|
switch(reg) {
|
||
|
case XED_REG_RAX:
|
||
|
case XED_REG_EAX:
|
||
|
case XED_REG_AX:
|
||
|
return 0xAABBCC00;
|
||
|
break;
|
||
|
case XED_REG_AL: // FOR XLAT
|
||
|
break;
|
||
|
|
||
|
case XED_REG_RCX:
|
||
|
case XED_REG_ECX:
|
||
|
case XED_REG_CX:
|
||
|
return 0xAABBCCDD;
|
||
|
break;
|
||
|
case XED_REG_RDX:
|
||
|
case XED_REG_EDX:
|
||
|
case XED_REG_DX:
|
||
|
break;
|
||
|
case XED_REG_RBX:
|
||
|
case XED_REG_EBX:
|
||
|
case XED_REG_BX:
|
||
|
return 0x11223344;
|
||
|
break;
|
||
|
case XED_REG_RSP:
|
||
|
case XED_REG_ESP:
|
||
|
case XED_REG_SP:
|
||
|
break;
|
||
|
case XED_REG_RBP:
|
||
|
case XED_REG_EBP:
|
||
|
case XED_REG_BP:
|
||
|
break;
|
||
|
case XED_REG_RSI:
|
||
|
case XED_REG_ESI:
|
||
|
case XED_REG_SI:
|
||
|
return 0x1122334455;
|
||
|
break;
|
||
|
case XED_REG_RDI:
|
||
|
case XED_REG_EDI:
|
||
|
case XED_REG_DI:
|
||
|
return 0x6655443322;
|
||
|
break;
|
||
|
case XED_REG_R8:
|
||
|
case XED_REG_R8D:
|
||
|
case XED_REG_R8W:
|
||
|
break;
|
||
|
case XED_REG_R9:
|
||
|
case XED_REG_R9D:
|
||
|
case XED_REG_R9W:
|
||
|
break;
|
||
|
case XED_REG_R10:
|
||
|
case XED_REG_R10D:
|
||
|
case XED_REG_R10W:
|
||
|
break;
|
||
|
case XED_REG_R11:
|
||
|
case XED_REG_R11D:
|
||
|
case XED_REG_R11W:
|
||
|
break;
|
||
|
case XED_REG_R12:
|
||
|
case XED_REG_R12D:
|
||
|
case XED_REG_R12W:
|
||
|
break;
|
||
|
case XED_REG_R13:
|
||
|
case XED_REG_R13D:
|
||
|
case XED_REG_R13W:
|
||
|
break;
|
||
|
case XED_REG_R14:
|
||
|
case XED_REG_R14D:
|
||
|
case XED_REG_R14W:
|
||
|
break;
|
||
|
case XED_REG_R15:
|
||
|
case XED_REG_R15D:
|
||
|
case XED_REG_R15W:
|
||
|
break;
|
||
|
case XED_REG_RIP:
|
||
|
return 0x7990100020003000ULL;
|
||
|
|
||
|
case XED_REG_EIP:
|
||
|
case XED_REG_IP:
|
||
|
break;
|
||
|
case XED_REG_CS:
|
||
|
case XED_REG_DS:
|
||
|
case XED_REG_ES:
|
||
|
case XED_REG_SS:
|
||
|
case XED_REG_FS:
|
||
|
case XED_REG_GS:
|
||
|
break;
|
||
|
default:
|
||
|
assert(0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
xed_uint64_t segment_callback(xed_reg_enum_t reg, void* context, xed_bool_t* error) {
|
||
|
/* for protected mode, this function returns the valid segment base values */
|
||
|
|
||
|
/* in reality, you'd have to return valid valies for each case */
|
||
|
/* THIS IS JUST AN EXAMPLE FOR TESTING AND DOES NOT RETURN REAL DATA */
|
||
|
|
||
|
(void) context; // pacify compiler
|
||
|
(void) error;
|
||
|
|
||
|
switch(reg) {
|
||
|
case XED_REG_CS:
|
||
|
case XED_REG_DS:
|
||
|
case XED_REG_ES:
|
||
|
case XED_REG_SS:
|
||
|
return 0;
|
||
|
case XED_REG_FS:
|
||
|
return 0;
|
||
|
break;
|
||
|
case XED_REG_GS:
|
||
|
return 0;
|
||
|
break;
|
||
|
default:
|
||
|
assert(0);
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
main(int argc, char** argv)
|
||
|
{
|
||
|
xed_error_enum_t xed_error;
|
||
|
|
||
|
xed_bool_t long_mode = 0;
|
||
|
xed_bool_t real_mode = 0;
|
||
|
xed_bool_t protected_16 = 0;
|
||
|
xed_state_t dstate;
|
||
|
unsigned int first_argv;
|
||
|
unsigned int bytes = 0;
|
||
|
unsigned char itext[XED_MAX_INSTRUCTION_BYTES];
|
||
|
unsigned int i;
|
||
|
unsigned int argcu = (unsigned int)argc;
|
||
|
unsigned int u;
|
||
|
xed_decoded_inst_t xedd;
|
||
|
#define BUFLEN 1000
|
||
|
char buffer[BUFLEN];
|
||
|
xed_bool_t ok;
|
||
|
unsigned int isyntax;
|
||
|
xed_syntax_enum_t syntax;
|
||
|
unsigned int memop_index = 0;
|
||
|
unsigned int memops = 0;
|
||
|
xed_uint64_t out_addr = 0;
|
||
|
|
||
|
xed_tables_init();
|
||
|
|
||
|
// register callbacks that provide actual values. These functions will
|
||
|
// be called by xed_agen() later on when values are needed.
|
||
|
xed_agen_register_callback( register_callback, segment_callback);
|
||
|
|
||
|
xed_state_zero(&dstate);
|
||
|
//xed_set_verbosity( 99 );
|
||
|
|
||
|
if (argcu > 2 && strcmp(argv[1], "-64") == 0)
|
||
|
long_mode = 1;
|
||
|
if (argcu > 2 && strcmp(argv[1], "-r") == 0)
|
||
|
real_mode = 1;
|
||
|
if (argcu > 2 && strcmp(argv[1], "-16") == 0)
|
||
|
protected_16 = 1;
|
||
|
|
||
|
if (long_mode) {
|
||
|
first_argv = 2;
|
||
|
dstate.mmode=XED_MACHINE_MODE_LONG_64;
|
||
|
}
|
||
|
else if (protected_16) {
|
||
|
first_argv = 2;
|
||
|
xed_state_init(&dstate,
|
||
|
XED_MACHINE_MODE_LEGACY_16,
|
||
|
XED_ADDRESS_WIDTH_16b,
|
||
|
XED_ADDRESS_WIDTH_16b);
|
||
|
}
|
||
|
else if (real_mode) {
|
||
|
first_argv = 2;
|
||
|
/* we say that real mode uses 16b addressing even though the
|
||
|
addresses returned are 20b long. */
|
||
|
xed_state_init(&dstate,
|
||
|
XED_MACHINE_MODE_REAL_16,
|
||
|
XED_ADDRESS_WIDTH_16b,
|
||
|
XED_ADDRESS_WIDTH_16b);
|
||
|
}
|
||
|
else {
|
||
|
first_argv=1;
|
||
|
xed_state_init(&dstate,
|
||
|
XED_MACHINE_MODE_LEGACY_32,
|
||
|
XED_ADDRESS_WIDTH_32b,
|
||
|
XED_ADDRESS_WIDTH_32b);
|
||
|
}
|
||
|
|
||
|
xed_decoded_inst_zero_set_mode(&xedd, &dstate);
|
||
|
for( i=first_argv ;i < argcu; i++) {
|
||
|
xed_uint8_t x = (xed_uint8_t)(xed_atoi_hex(argv[i]));
|
||
|
assert(bytes < XED_MAX_INSTRUCTION_BYTES);
|
||
|
itext[bytes++] = x;
|
||
|
}
|
||
|
if (bytes == 0) {
|
||
|
fprintf(stderr, "Must supply some hex bytes\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
printf("PARSING BYTES: ");
|
||
|
for( u=0;u<bytes; u++)
|
||
|
printf("%02x ", XED_STATIC_CAST(unsigned int,itext[u]));
|
||
|
printf("\n");
|
||
|
|
||
|
// call XED decode
|
||
|
|
||
|
xed_error = xed_decode(&xedd,
|
||
|
XED_REINTERPRET_CAST(const xed_uint8_t*,itext),
|
||
|
bytes);
|
||
|
switch(xed_error)
|
||
|
{
|
||
|
case XED_ERROR_NONE:
|
||
|
break;
|
||
|
case XED_ERROR_BUFFER_TOO_SHORT:
|
||
|
fprintf(stderr,"Not enough bytes provided\n");
|
||
|
exit(1);
|
||
|
case XED_ERROR_GENERAL_ERROR:
|
||
|
fprintf(stderr,"Could not decode given input.\n");
|
||
|
exit(1);
|
||
|
default:
|
||
|
fprintf(stderr,"Unhandled error code %s\n", xed_error_enum_t2str(xed_error));
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
// print the output a few different ways
|
||
|
printf("iclass: %s\n",
|
||
|
xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(&xedd)));
|
||
|
printf("iform: %s\n",
|
||
|
xed_iform_enum_t2str(xed_decoded_inst_get_iform_enum(&xedd)));
|
||
|
|
||
|
for(isyntax= XED_SYNTAX_XED; isyntax < XED_SYNTAX_LAST; isyntax++) {
|
||
|
syntax = XED_STATIC_CAST(xed_syntax_enum_t, isyntax);
|
||
|
ok = xed_format_context(syntax, &xedd, buffer, BUFLEN, 0, 0, 0);
|
||
|
if (ok)
|
||
|
printf("%s syntax: %s\n", xed_syntax_enum_t2str(syntax), buffer);
|
||
|
else
|
||
|
printf("Error disassembling %s syntax\n", xed_syntax_enum_t2str(syntax));
|
||
|
}
|
||
|
|
||
|
memops = xed_decoded_inst_number_of_memory_operands(&xedd);
|
||
|
printf("\nNumber of memory operands: %d\n", (int)memops);
|
||
|
|
||
|
// call the address generation (agen) calculator for each memop.
|
||
|
// It will call the callbacks you registered at top of main().
|
||
|
|
||
|
for(memop_index=0;memop_index<memops;memop_index++) {
|
||
|
// The "context" passed to your registered callbacks when they are asked
|
||
|
// to produce values. In this example we don't require a real context.
|
||
|
void* context = 0;
|
||
|
xed_error = xed_agen(&xedd, memop_index, context, &out_addr);
|
||
|
if (xed_error != XED_ERROR_NONE) {
|
||
|
fprintf(stderr,"Agen error code %s\n", xed_error_enum_t2str(xed_error));
|
||
|
exit(1);
|
||
|
}
|
||
|
printf("\tMemory agen%d: 0x" XED_FMT_LX16 "\n", (int)memop_index, out_addr);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|