x86_instrumentation_subscribe
interface is an x86
specific complement to the cpu_instrumentation_subscribe
interface. It is implemented by processor objects that support
instrumentation. It has the same requirements as the
cpu_instrumentation_subscribe
interface.
SIM_INTERFACE(x86_instrumentation_subscribe) { cpu_cb_handle_t *(*register_mode_switch_cb)( conf_object_t *cpu, conf_object_t *connection, x86_mode_switch_cb_t cb, lang_void *user_data); cpu_cb_handle_t *(*register_illegal_instruction_cb)( conf_object_t *NOTNULL cpu, conf_object_t *connection, cpu_instruction_decoder_cb_t cb, cpu_instruction_disassemble_cb_t disass_cb, lang_void *data); }; #define X86_INSTRUMENTATION_SUBSCRIBE_INTERFACE \ "x86_instrumentation_subscribe"
The register_mode_switch_cb method is used to register a callback that is called whenever the processor cpu changes execution mode. The connection argument is the user object that registers the callback. This object will be passed to the callback when it is called. cb is the callback and user_data is user data for the callback. The signature of the callback looks like this:
typedef void (*x86_mode_switch_cb_t)( conf_object_t *obj, conf_object_t *cpu, x86_detailed_exec_mode_t mode, lang_void *user_data);
The obj is the connection object that registered the
callback. new_mode argument contains the new mode. The possible
modes available are captured in the x86_detailed_exec_mode_t
type:
typedef enum { X86_Detailed_Exec_Mode_Real_16, X86_Detailed_Exec_Mode_Real_32, X86_Detailed_Exec_Mode_V86, X86_Detailed_Exec_Mode_Protected_16, X86_Detailed_Exec_Mode_Protected_32, X86_Detailed_Exec_Mode_Protected_64, X86_Detailed_Exec_Mode_Compatibility_16, X86_Detailed_Exec_Mode_Compatibility_32, } x86_detailed_exec_mode_t;
The user_data is the user data associated with the callback.
register_illegal_instruction_cb lets a user to implement new
instructions. The cb argument is a callback function that will be
called every time Simics does not decode an instruction. Allows new x86
instructions to be implemented which otherwise cause illegal instruction
exception. Compared to register_instruction_decoder_cb method of
cpu_instrumentation_subscribe
interface this interface cannot
change any instruction that correctly decodes according to the existing
instruction set architecture. From this callback the user can accept the
instruction or deny it. In most cases this only happens once per instruction
address since Simics usually caches decoding results in the internal
instruction cache. If the cache is flushed the callback may be called again.
This instrumentation feature (if used alone) does not prevent VMP execution
since illegal instructions cause exit while running inside VMP mode.
The callback signature looks like this:
typedef int (*cpu_instruction_decoder_cb_t)( conf_object_t *obj, conf_object_t *cpu, decoder_handle_t *decoder_handle, instruction_handle_t *iq_handle, lang_void *user_data);
The instruction bytes are read by using the get_instruction_bytes
method of the cpu_instruction_query
interface together with
the iq_handle. The returned value is of a
cpu_bytes_t
type. To access the bytes use the data
and
the size
members in the returned value.
If the decoder requires more bytes (i.e., because the new instruction is longer), a negative integer value should be returned by the cb function, indicating the number of bytes needed. For example, if the available bytes are 3 but the decoder need at least 4 bytes, -4 should be returned. The callback will then be called again with more available bytes (this can be repeated if the new instruction requires even more bytes at this point). Note that requesting more data than actual needed can cause spurious page faults if the data crosses a page boundary.
If the instruction is accepted by the callback a positive integer number
should be returned corresponding to the length of the instruction. In this
case the register_emulation_cb method of the
cpu_instruction_decoder
interface should be called to set the
actual (user) function that Simics will call each time the instruction is
executed.
If the cb callback should ignore the instruction the number 0 should be returned. This means that any other registered decoder will have a chance to decode the instruction. If no decoder accepts it, Simics will generate illegal instruction exception.
The register_emulation_cb method also needs the
decoder_handle which is available in the dedoder callback. For
more information, see the documentation of the
cpu_instruction_decoder
interface.
A disass_cb argument should also be passed to the register_illegal_instruction_cb method. This function is called every time Simics wants to disassemble an instruction. For every accepted instruction a corresponding disassembly string should be returned by this function. It has the following signature:
typedef tuple_int_string_t (*cpu_instruction_disassemble_cb_t)( conf_object_t *obj, conf_object_t *cpu, generic_address_t addr, cpu_bytes_t bytes);
obj is the object registering the
register_illegal_instruction_cb and cpu is the
processor disassembling the instruction. addr is the address of
the instruction in a generic form. This means that it is typically a
physical address or a logical address depending on the context of the
disassembling. The address can be used for offset calculations, i.e.,
displaying an absolute address instead of a relative one, for example in a
branch instruction. The bytes argument should be used to read
instruction bytes. The return value is of type
tuple_int_string_t
and should be filled with the instruction
length and an allocated (e.g., malloc) string representing the disassembly
of the instruction. The ownership of the string is transferred to the
calling environment which will free it when it is no longer needed.
If too few bytes are passed for the instruction to be disassembled a negative value should be returned for the length indicating the needed bytes. The disass_cb is then called again with more bytes. If the instruction is rejected a length of 0 should be returned and the string should be set to NULL.
To remove the callback used one of the methods remove_callback or
remove_connection_callbacks in the
cpu_instrumentation_subscribe
interface.
The callback can also be enabled and disabled with the corresponding methods
in the cpu_instrumentation_subscribe
interface.