cpu_cached_instruction_cb_t
callback where there is a
valid ci_handle. The callback is installed by calling the
register_cached_instruction_cb method in the
cpu_instrumentation_subscribe
interface. The signature of the
callback function looks like this:
typedef void (*cpu_cached_instruction_cb_t)( conf_object_t *obj, conf_object_t *cpu, cached_instruction_handle_t *ci_handle, instruction_handle_t *iq_handle, lang_void *user_data);
When the callback is installed Simics will call it every time an instruction is put into the internal instruction cache, which might have different entries for different execution modes. For example, in an unlikely case where the same instruction is executed in 32-bit mode and later in 64-bit mode (running an x86 processor for instance), this callback will be called twice, one time for each mode. This allows the user to install specific callbacks for this specific instruction and apply filtering based on instruction types, etc. This approach is more efficient than doing dynamic filtering in the instruction and read/write callbacks installed by the cpu_instrumentation_subscribe interface.
The iq_handle together with the
cpu_instruction_query
interface let a user examine
instruction properties. The user_data is the user data for the
callback.
SIM_INTERFACE(cpu_cached_instruction) { void (*register_instruction_before_cb)( conf_object_t *cpu, cached_instruction_handle_t *ci_handle, cpu_instruction_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); void (*register_instruction_after_cb)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, cpu_instruction_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); void (*register_read_before_cb)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, cpu_memory_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); void (*register_read_after_cb)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, cpu_memory_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); void (*register_write_before_cb)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, cpu_memory_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); void (*register_write_after_cb)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, cpu_memory_cb_t cb, lang_void *user_data, cpu_callback_free_user_data_cb_t free_cb); #ifndef PYWRAP void (*add_counter)( conf_object_t *obj, cached_instruction_handle_t *ci_handle, uint64 *counter, bool use_atomic_increment); #endif }; #define CPU_CACHED_INSTRUCTION_INTERFACE "cpu_cached_instruction"
The method register_instruction_before_cb installs a callback that is called before the cached instruction is executed. The ci_handle is used to bind the callback to the cached instruction. The user_data is the callback's user data, and a callback for freeing the data is also available. The free_cb looks like this:
typedef void (*cpu_callback_free_user_data_cb_t)( conf_object_t *obj, conf_object_t *cpu, lang_void *user_data);
It is called when Simics wants to free cached instructions, which can happen in various situations. obj is the connection object that should free the data. The callback may be NULL if not needed.
The cb callback type is the same as used for instructions in the
cpu_instrumentation_subscribe
interface:
typedef void (*cpu_instruction_cb_t)( conf_object_t *obj, conf_object_t *cpu, instruction_handle_t *handle, lang_void *user_data);
The object obj is the user object that registers the callback and
cpu is the processor object executing the instruction. The
handle can be used to query more data about the instruction. See
the cpu_instruction_query
interface for more information. The
user_data is the user data associated with the callback.
The user data is a convenient location for storing information about the instruction, such as user specific decode information, etc. The user data is private for each installed callback.
The cached information about the instruction is bound to its physical address so the logical address cannot typically be saved since it may vary between calls (if the MMU-mapping has changed).
register_instruction_after_cb installs a callback that is called
after a cached instruction is executed. Otherwise it works in the same as
the before variant.
However, reading the program counter register for a control flow instruction
in this callback will reflect the new location, whereas using the
cpu_instruction_query
for reading out the instruction address
will still return the address of the control flow instruction.
register_read_before_cb installs a callback that is called before
each read operation in the cached instruction. The callback is the
same as used for read and writes in the
cpu_instrumentation_subscribe
interface:
typedef void (*cpu_memory_cb_t)( conf_object_t *obj, conf_object_t *cpu, memory_handle_t *handle, lang_void *user_data);
As for instructions, obj is the object that registered the
callback and cpu is the processor doing the access. The
handle can be used to further operate on the access by using the
cpu_memory_query
interface. The
user_data and the free_cb arguments to
register_read_before_cb can be used to store user data for the
read operations in the cached instruction. The user data is private for each
installed callback but is shared between all read before operations in the
instruction.
register_read_after_cb installs a callback that is called after each read operation in the cached instruction. The user data is private for each installed callback but is shared between all read after operations in the instruction. Otherwise it works in the same way as the before variant.
register_write_before_cb and register_write_after_cb installs callbacks that is called before and after each write operation in the cached instructions. Otherwise they work in the same way as the read variants.
Note that installing a read or write callback on an instruction without any memory operations will be useless.
The add_counter method can be used to add simple counters for this particular instruction. The counter argument is a pointer to a 64 bit counter value that will be incremented each time the instruction is executed. This is the same thing (but more efficient) as registering a callback through the register_instruction_before_cb method and increasing the counter each time it is called.
Passing true for the argument use_atomic_increment makes the increment of the counter atomic, which may be useful if the tool cannot have an instrumentation connection per processor. This will however be slower due to the nature of atomic instructions.
The location of the counter value can only be removed/deallocated after a
call to either the remove_callback method (passing the
cpu_cb_handle_t
returned by
register_cached_instruction_cb), or to the
remove_connection_callbacks method (with the connection object as
the argument) in the cpu_instrumentation_subscribe interface
.
This method is not available in Python.
The instrumentation_order
interface cannot be used to
reorder callbacks installed with the cpu_cached_instruction
interface. The cached callbacks are always called in same order as the
cpu_cached_instruction_cb_t callback that installed them,
and before any callback installed by the corresponding methods in the
cpu_instrumentation_subscribe
.
cpu_instrumentation_subscribe
interface.