From 95481bff5fa1e23b946e6758891e8b76751fa4c6 Mon Sep 17 00:00:00 2001 From: jamcleod Date: Fri, 15 Oct 2021 00:13:06 -0400 Subject: [PATCH 1/5] Add user data context to base callbacks --- panda/include/panda/callbacks/cb-defs.h | 952 ++++++++++++++++++ .../include/panda/callbacks/cb-helper-impl.h | 4 +- panda/include/panda/callbacks/cb-macros.h | 50 +- panda/include/panda/callbacks/cb-support.h | 2 +- .../include/panda/callbacks/cb-trampolines.h | 83 ++ panda/include/panda/plugin.h | 5 +- panda/src/callbacks.c | 87 +- panda/src/cb-support.c | 62 +- 8 files changed, 1224 insertions(+), 21 deletions(-) create mode 100644 panda/include/panda/callbacks/cb-trampolines.h diff --git a/panda/include/panda/callbacks/cb-defs.h b/panda/include/panda/callbacks/cb-defs.h index 987f62dc205..6170f6d699f 100644 --- a/panda/include/panda/callbacks/cb-defs.h +++ b/panda/include/panda/callbacks/cb-defs.h @@ -1055,6 +1055,958 @@ typedef union panda_cb { } panda_cb; +typedef union panda_cb_with_context { + /* Callback ID: PANDA_CB_BEFORE_BLOCK_EXEC_INVALIDATE_OPT + + before_block_exec_invalidate_opt: + Called before execution of every basic block, with the option + to invalidate the TB. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we are about to execute + + Helper call location: cpu-exec.c (indirectly) + + Return value: + true if we should invalidate the current translation block + and retranslate, false otherwise. + */ + bool (*before_block_exec_invalidate_opt)(void* context, CPUState *env, TranslationBlock *tb); + + /* Callback ID: PANDA_CB_BEFORE_TCG_CODEGEN + + before_tcg_codegen: + Called before host code generation for every basic block. Enables + inspection and modification of the TCG block after lifting from guest + code. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB about to be compiled + + Helper call location: translate-all.c + + Return value: + None + */ + void (*before_tcg_codegen)(void* context, CPUState *env, TranslationBlock *tb); + + /* Callback ID: PANDA_CB_BEFORE_BLOCK_EXEC + + before_block_exec: + Called before execution of every basic block. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we are about to execute + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*before_block_exec)(void* context, CPUState *env, TranslationBlock *tb); + + /* Callback ID: PANDA_CB_AFTER_BLOCK_EXEC + + after_block_exec: + Called after execution of every basic block. + If exitCode > TB_EXIT_IDX1, then the block exited early. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we just executed + uint8_t exitCode: why the block execution exited + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*after_block_exec)(void* context, CPUState *env, TranslationBlock *tb, uint8_t exitCode); + + /* Callback ID: PANDA_CB_BEFORE_BLOCK_TRANSLATE + + before_block_translate: + Called before translation of each basic block. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC we are about to translate + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*before_block_translate)(void* context, CPUState *env, target_ptr_t pc); + + /* Callback ID: PANDA_CB_AFTER_BLOCK_TRANSLATE + + after_block_translate: + Called after the translation of each basic block. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we just translated + + Helper call location: cpu-exec.c + + Return value: + none + + Notes: + This is a good place to perform extra passes over the generated + code (particularly by manipulating the LLVM code). + FIXME: How would this actually work? By this point the out ASM + has already been generated. Modify the IR and then regenerate? + */ + void (*after_block_translate)(void* context, CPUState *env, TranslationBlock *tb); + + /* Callback ID: PANDA_CB_AFTER_CPU_EXEC_ENTER + + after_cpu_exec_enter: + Called after cpu_exec calls cpu_exec_enter function. + + Arguments: + CPUState *env: the current CPU state + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*after_cpu_exec_enter)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_BEFORE_CPU_EXEC_EXIT + + before_cpu_exec_exit: + Called before cpu_exec calls cpu_exec_exit function. + + Arguments: + CPUState *env: the current CPU state + bool ranBlock: true if ran a block since previous cpu_exec_enter + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*before_cpu_exec_exit)(void* context, CPUState *env, bool ranBlock); + + /* Callback ID: PANDA_CB_INSN_TRANSLATE + + insn_translate: + Called before the translation of each instruction. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC we are about to translate + + Helper call location: panda/target/ARCH/translate.c + + Return value: + true if PANDA should insert instrumentation into the generated code, + false otherwise + + Notes: + This allows a plugin writer to instrument only a small number of + instructions, avoiding the performance hit of instrumenting everything. + If you do want to instrument every single instruction, just return + true. See the documentation for PANDA_CB_INSN_EXEC for more detail. + */ + bool (*insn_translate)(void* context, CPUState *env, target_ptr_t pc); + + /* Callback ID: PANDA_CB_INSN_EXEC + + insn_exec: + Called before execution of any instruction identified by the + PANDA_CB_INSN_TRANSLATE callback. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC we are about to execute + + Helper call location: TBA + + Return value: + unused + + Notes: + This instrumentation is implemented by generating a call to a + helper function just before the instruction itself is generated. + This is fairly expensive, which is why it's only enabled via + the PANDA_CB_INSN_TRANSLATE callback. + */ + int (*insn_exec)(void* context, CPUState *env, target_ptr_t pc); + + /* Callback ID: PANDA_CB_AFTER_INSN_TRANSLATE + + after_insn_translate: + Called after the translation of each instruction. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the next guest PC we've translated + + Helper call location: panda/target/ARCH/translate.c + + Return value: + true if PANDA should insert instrumentation into the generated code, + false otherwise + + Notes: + See `insn_translate`, callbacks are registered via PANDA_CB_AFTER_INSN_EXEC + */ + bool (*after_insn_translate)(void* context, CPUState *env, target_ptr_t pc); + + /* Callback ID: PANDA_CB_AFTER_INSN_EXEC + + after_insn_exec: + Called after execution of an instruction identified by the + PANDA_CB_AFTER_INSN_TRANSLATE callback + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the next guest PC already executed + + Helper call location: TBA + + Return value: + unused + + Notes: + See `insn_exec`. Enabled via the PANDA_CB_AFTER_INSN_TRANSLATE callback. + */ + int (*after_insn_exec)(void* context, CPUState *env, target_ptr_t pc); + + /* Callback ID: PANDA_CB_VIRT_MEM_BEFORE_READ + + virt_mem_before_read: + Called before memory is read. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the read + target_ptr_t addr: the (virtual) address being read + size_t size: the size of the read + + Helper call location: TBA + + Return value: + none + */ + void (*virt_mem_before_read)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size); + + /* Callback ID: PANDA_CB_VIRT_MEM_BEFORE_WRITE + + virt_mem_before_write: + Called before memory is written. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the write + target_ptr_t addr: the (virtual) address being written + size_t size: the size of the write + uint8_t *buf: pointer to the data that is to be written + + Helper call location: TBA + + Return value: + none + */ + void (*virt_mem_before_write)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_PHYS_MEM_BEFORE_READ + + phys_mem_before_read: + Called after memory is read. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the read + target_ptr_t addr: the (physical) address being read + size_t size: the size of the read + + Helper call location: TBA + + Return value: + none + */ + void (*phys_mem_before_read)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size); + + /* Callback ID: PANDA_CB_PHYS_MEM_BEFORE_WRITE + + phys_mem_write: + Called before memory is written. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the write + target_ptr_t addr: the (physical) address being written + size_t size: the size of the write + uint8_t *buf: pointer to the data that is to be written + + Helper call location: TBA + + Return value: + none + */ + void (*phys_mem_before_write)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_VIRT_MEM_AFTER_READ + + virt_mem_after_read: + Called after memory is read. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the read + target_ptr_t addr: the (virtual) address being read + size_t size: the size of the read + uint8_t *buf: pointer to data just read + + Helper call location: TBA + + Return value: + none + */ + void (*virt_mem_after_read)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_VIRT_MEM_AFTER_WRITE + + virt_mem_after_write: + Called after memory is written. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the write + target_ptr_t addr: the (virtual) address being written + size_t size: the size of the write + uint8_t *buf: pointer to the data that was written + + Helper call location: TBA + + Return value: + none + */ + void (*virt_mem_after_write)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_PHYS_MEM_AFTER_READ + + phys_mem_after_read: + Called after memory is read. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the read + target_ptr_t addr: the (physical) address being read + size_t size: the size of the read + uint8_t *buf: pointer to data just read + + Helper call location: TBA + + Return value: + none + */ + void (*phys_mem_after_read)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_PHYS_MEM_AFTER_WRITE + + phys_mem_write: + Called after memory is written. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t pc: the guest PC doing the write + target_ptr_t addr: the (physical) address being written + size_t size: the size of the write + uint8_t *buf: pointer to the data that was written + + Helper call location: TBA + + Return value: + none + */ + void (*phys_mem_after_write)(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + + /* Callback ID: PANDA_CB_MMIO_AFTER_READ + + mmio_after_read: + Called after MMIO memory is read. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t physaddr: the physical address being read from + target_ptr_t vaddr: the virtual address being read from + size_t size: the size of the read + uin64_t *val: the value being read + + Helper call location: cputlb.c + + Return value: + none + */ + void (*mmio_after_read)(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); + + /* Callback ID: PANDA_CB_MMIO_BEFORE_WRITE + + mmio_before_write: + Called after MMIO memory is written to. + + Arguments: + CPUState *env: the current CPU state + target_ptr_t physaddr: the physical address being written to + target_ptr_t vaddr: the virtual address being written to + size_t size: the size of the write + uin64_t *val: the value being written + + Helper call location: cputlb.c + + Return value: + none + */ + void (*mmio_before_write)(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); + + /* Callback ID: PANDA_CB_HD_READ + hd_read : called when there is a hard drive read + + Note: this was added to panda_cb_type enum but no callback prototype inserted + Here is a stub. I'm not sure what the args should be. + Arguments + CPUState *env + */ + + void (*hd_read)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_HD_WRITE + hd_write : called when there is a hard drive write + + Note: this was added to panda_cb_type enum but no callback prototype inserted + Here is a stub. I'm not sure what the args should be. + Arguments + CPUState *env + */ + + void (*hd_write)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_GUEST_HYPERCALL + + guest_hypercall: + Called when a program inside the guest makes a hypercall to pass + information from inside the guest to a plugin + + Arguments: + CPUState *env: the current CPU state + + Helper call location: target/i386/misc_helper.c + + Return value: + true if the callback has processed the hypercall, false if the + hypercall has been ignored. + + Notes: + On x86, this is called whenever CPUID is executed. On ARM, the + MCR instructions is used. Plugins should check for magic values + in the registers to determine if it really is a guest hypercall. + Parameters can be passed in other registers. If the plugin + processes the hypercall, it should return true so the execution + of the normal instruction is skipped. + */ + bool (*guest_hypercall)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_MONITOR + + monitor: + Called when someone uses the plugin_cmd monitor command. + + Arguments: + Monitor *mon: a pointer to the Monitor + const char *cmd: the command string passed to plugin_cmd + + Helper call location: TBA + + Return value: + unused + + Notes: + The command is passed as a single string. No parsing is performed + on the string before it is passed to the plugin, so each plugin + must parse the string as it deems appropriate (e.g. by using strtok + and getopt) to do more complex option processing. + It is recommended that each plugin implementing this callback respond + to the "help" message by listing the commands supported by the plugin. + Note that every loaded plugin will have the opportunity to respond to + each plugin_cmd; thus it is a good idea to ensure that your plugin's + monitor commands are uniquely named, e.g. by using the plugin name + as a prefix ("sample_do_foo" rather than "do_foo"). + */ + int (*monitor)(void* context, Monitor *mon, const char *cmd); + + + /* Callback ID: PANDA_CB_CPU_RESTORE_STATE + + cpu_restore_state: + Called inside of cpu_restore_state(), when there is a CPU + fault/exception. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the current translation block + + Helper call location: translate-all.c + + Return value: + none + */ + void (*cpu_restore_state)(void* context, CPUState *env, TranslationBlock *tb); + + /* Callback ID: PANDA_CB_BEFORE_LOADVM + + before_loadvm: + Called at start of replay, before loadvm is called. This allows + us to hook devices' loadvm handlers. Remember to unregister the + existing handler for the device first. See the example in the + sample plugin. + + Arguments: + none + + Helper call location: TBA + + Return value: + unused + */ + int (*before_loadvm)(void* context); + + /* Callback ID: PANDA_CB_ASID_CHANGED + + asid_changed: + Called when asid changes. + + Arguments: + CPUState *env: pointer to CPUState + target_ptr_t oldval: old asid value + target_ptr_t newval: new asid value + + Helper call location: target/i386/helper.c, target/arm/helper.c + + Return value: + true if the asid should be prevented from being changed + false otherwise + + Notes: + The callback is only invoked implemented for x86 and ARM. + This should break plugins which rely on it to detect context + switches in any other architecture. + */ + bool (*asid_changed)(void* context, CPUState *env, target_ptr_t oldval, target_ptr_t newval); + + /* Callback ID: PANDA_CB_REPLAY_HD_TRANSFER, + + replay_hd_transfer: + In replay only. Some kind of data transfer involving hard drive. + + Arguments: + CPUState *env: pointer to CPUState + uint32_t type: type of transfer (Hd_transfer_type) + target_ptr_t src_addr: address for src + target_ptr_t dest_addr: address for dest + size_t num_bytes: size of transfer in bytes + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + + Helper call location: TBA + + Notes: + Unlike most callbacks, this is neither a "before" or "after" callback. + In replay the transfer doesn't really happen. We are *at* the point at + which it happened, really. + */ + void (*replay_hd_transfer)(void* context, CPUState *env, uint32_t type, target_ptr_t src_addr, target_ptr_t dest_addr, size_t num_bytes); + + /* Callback ID: PANDA_CB_REPLAY_BEFORE_DMA, + + replay_before_dma: + In replay only. We are about to dma between qemu buffer and + guest memory. + + Arguments: + CPUState *env: pointer to CPUState + const uint8_t *buf: pointer to the QEMU's device buffer ussed in the transfer + hwaddr addr: address written to in the guest RAM + size_t size: size of transfer + bool is_write: indicates whether the DMA transfer writes to memory + + Helper call location: exec.c + + Return value: + none + */ + void (*replay_before_dma)(void* context, CPUState *env, const uint8_t *buf, hwaddr addr, size_t size, bool is_write); + + /* Callback ID: PANDA_CB_REPLAY_AFTER_DMA, + + In replay only, we are about to dma between qemu buffer and guest memory + + Arguments: + CPUState *env: pointer to CPUState + const uint8_t *buf: pointer to the QEMU's device buffer ussed in the transfer + hwaddr addr: address written to in the guest RAM + size_t size: size of transfer + bool is_write: indicates whether the DMA transfer writes to memory + + Helper call location: exec.c + + Return value: + none + */ + void (*replay_after_dma)(void* context, CPUState *env, const uint8_t *buf, hwaddr addr, size_t size, bool is_write); + + /* Callback ID: PANDA_CB_REPLAY_HANDLE_PACKET, + + In replay only, we have a packet (incoming / outgoing) in hand. + + Arguments: + CPUState *env: pointer to CPUState + uint8_t *buf: buffer containing packet data + size_t size: num bytes in buffer + uint8_t direction: either `PANDA_NET_RX` or `PANDA_NET_TX` + uint64_t buf_addr_rec: the address of `buf` at the time of recording + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + + Notes: + `buf_addr_rec` corresponds to the address of the device buffer of + the emulated NIC. I.e. it is the address of a VM-host-side buffer. + It is useful for implementing network tainting in an OS-agnostic + way, in conjunction with taint2_label_io(). + + FIXME: The `buf_addr_rec` maps to the `uint8_t *buf` field of the + internal `RR_handle_packet_args` struct. The field is dumped/loaded + to/from the trace without proper serialization/deserialization. As + a result, a 64bit build of PANDA will not be able to process traces + produced by a 32bit of PANDA, and vice-versa. + There are more internal structs that suffer from the same issue. + This is an oversight that will eventually be fixed. But as the + real impact is minimal (virtually nobody uses 32bit builds), + the fix has a very low priority in the bugfix list. + */ + void (*replay_handle_packet)(void* context, CPUState *env, uint8_t *buf, size_t size, uint8_t direction, uint64_t buf_addr_rec); + + /* Callback ID: PANDA_CB_REPLAY_NET_TRANSFER, + + replay_net_transfer: + In replay only, some kind of data transfer within the network card + (currently, only the E1000 is supported). + + Arguments: + CPUState *env: pointer to CPUState + uint32_t type: type of transfer (Net_transfer_type) + uint64_t src_addr: address for src + uint64_t dest_addr: address for dest + size_t num_bytes: size of transfer in bytes + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + + Notes: + Unlike most callbacks, this is neither a "before" or "after" callback. + In replay the transfer doesn't really happen. We are *at* the point at + which it happened, really. + Also, the src_addr and dest_addr may be for either host (ie. a location + in the emulated network device) or guest, depending upon the type. + */ + void (*replay_net_transfer)(void* context, CPUState *env, uint32_t type, uint64_t src_addr, uint64_t dest_addr, size_t num_bytes); + + /* Callback ID: PANDA_CB_REPLAY_SERIAL_RECEIVE, + + replay_serial_receive: + In replay only, called when a byte is received on the serial port. + + Arguments: + CPUState *env: pointer to CPUState + target_ptr_t fifo_addr: address of the data within the fifo + uint8_t value: value received + + Helper call location: panda/src/rr/rr_log.c + + Return value: + unused + */ + void (*replay_serial_receive)(void* context, CPUState *env, target_ptr_t fifo_addr, uint8_t value); + + /* Callback ID: PANDA_CB_REPLAY_SERIAL_READ, + + replay_serial_read: + In replay only, called when a byte read from the serial RX FIFO + + Arguments: + CPUState *env: pointer to CPUState + target_ptr_t fifo_addr: address of the data within the fifo (source) + uint32_t port_addr: address of the IO port where data is being read (destination) + uint8_t value: value read + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + */ + void (*replay_serial_read)(void* context, CPUState *env, target_ptr_t fifo_addr, uint32_t port_addr, uint8_t value); + + /* Callback ID: PANDA_CB_REPLAY_SERIAL_SEND, + + replay_serial_send: + In replay only, called when a byte is sent on the serial port. + + Arguments: + CPUState *env: pointer to CPUState + target_ptr_t fifo_addr: address of the data within the fifo + uint8_t value: value received + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + */ + void (*replay_serial_send)(void* context, CPUState *env, target_ptr_t fifo_addr, uint8_t value); + + /* Callback ID: PANDA_CB_REPLAY_SERIAL_WRITE, + + In replay only, called when a byte written to the serial TX FIFO + + Arguments: + CPUState *env: pointer to CPUState + target_ptr_t fifo_addr: address of the data within the fifo (source) + uint32_t port_addr: address of the IO port where data is being read (destination) + uint8_t value: value read + + Helper call location: panda/src/rr/rr_log.c + + Return value: + none + */ + void (*replay_serial_write)(void* context, CPUState *env, target_ptr_t fifo_addr, uint32_t port_addr, uint8_t value); + + /* Callback ID: PANDA_CB_AFTER_MACHINE_INIT + + after_machine_init: + Called right after the machine has been initialized, but before + any guest code runs. + + Arguments: + void *cpu_env: pointer to CPUState + + Helper call location: TBA + + Return value: + none + + Notes: + This callback allows initialization of components that need + access to the RAM, CPU object, etc. E.g. for the taint2 plugin, + this is the appropriate place to call taint2_enable_taint(). + */ + void (*after_machine_init)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_AFTER_LOADVM + + after_loadvm: + Called right after a snapshot has been loaded (either with loadvm or replay initialization), + but before any guest code runs. + + Arguments: + void *cpu_env: pointer to CPUState + + Return value: + none + + */ + void (*after_loadvm)(void* context, CPUState *env); + + /* Callback ID: PANDA_CB_TOP_LOOP + + top_loop: + Called at the top of the loop that manages emulation. + + Arguments: + CPUState *env: pointer to CPUState + + Helper call location: cpus.c + + Return value: + unused + */ + void (*top_loop)(void* context, CPUState *env); + /* Callback ID: PANDA_CB_DURING_MACHINE_INIT + + during_machine_init: Called in the middle of machine initialization + + Arguments: + MachineState *machine: pointer to the machine state + + Return value: + None + */ + + void (*during_machine_init)(void* context, MachineState *machine); + + /* Callback ID: PANDA_CB_MAIN_LOOP_WAIT + + main_loop_wait: Called in IO thread in place where monitor cmds are processed + + Arguments: + None + + Return value: + None + */ + + void (*main_loop_wait)(void* context); + + /* Callback ID: PANDA_CB_PRE_SHUTDOWN + + pre_shutdown: Called just before qemu shuts down + + Arguments: + None + + Return value: + None + */ + void (*pre_shutdown)(void* context); + + /* Callback ID: PANDA_CB_UNASSIGNED_IO_READ + + unassigned_io_read: Called when the guest attempts to read from an unmapped peripheral via MMIO + + Arguments: + pc: Guest program counter at time of write + addr: Physical address written to + size: Size of write + val: Pointer to a buffer that will be passed to the guest as the result of the read + + Return value: + True if value read was changed by a PANDA plugin and should be returned + False if error-logic (invalid write) should be run + */ + bool (*unassigned_io_read)(void* context, CPUState *env, target_ptr_t pc, hwaddr addr, size_t size, uint64_t *val); + + /* Callback ID: PANDA_CB_UNASSIGNED_IO_WRITE + + unassigned_io_write: Called when the guest attempts to write to an unmapped peripheral via MMIO + + Arguments: + pc: Guest program counter at time of write + addr: Physical address written to + size: Size of write + val: Data being written, up to 8 bytes + + Return value: + True if the write should be allowed without error + False if normal behavior should be used (error-logic) + */ + bool (*unassigned_io_write)(void* context, CPUState *env, target_ptr_t pc, hwaddr addr, size_t size, uint64_t val); + + + /* Callback ID: PANDA_CB_BEFORE_HANDLE_EXCEPTION + + before_handle_exception: Called just before we are about to + handle an exception. + + Note: only called for cpu->exception_index > 0 + + Arguments: + exception_index (the current exception number) + + Return value: + a new exception_index. + + Note: There might be more than one callback for this location. + First callback that returns an exception index that *differs* + from the one passed as an arg wins. That is what we return as + the new exception index, which will replace + cpu->exception_index + + */ + + int32_t (*before_handle_exception)(void* context, CPUState *cpu, int32_t exception_index); + + /* Callback ID: PANDA_CB_BEFORE_HANDLE_INTERRUPT + + before_handle_interrupt: Called just before we are about to + handle an interrupt. + + Arguments: + interrupt request + + Return value: + new interrupt_rquest + + Note: There might be more than one callback for this location. + First callback that returns an interrupt_request that *differs* + from the one passed as an arg wins. + + */ + + + int32_t (*before_handle_interrupt)(void* context, CPUState *cpu, int32_t interrupt_request); + + /* Callback ID: PANDA_CB_START_BLOCK_EXEC + + start_block_exec: + This is like before_block_exec except its part of the TCG stream. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we are executing + + Helper call location: cpu-exec.c + + Return value: + none + */ + + void (*start_block_exec)(void* context, CPUState *cpu, TranslationBlock* tb); + + /* Callback ID: PANDA_CB_END_BLOCK_EXEC + + end_block_exec: + This is like after_block_exec except its part of the TCG stream. + + Arguments: + CPUState *env: the current CPU state + TranslationBlock *tb: the TB we are executing + + Helper call location: cpu-exec.c + + Return value: + none + */ + void (*end_block_exec)(void* context, CPUState *cpu, TranslationBlock* tb); + + /* cbaddr is a dummy union member. + + This union only contains function pointers. + Using the cbaddr member one can compare if two union instances + point to the same callback function. In principle, any other + member could be used instead. + However, cbaddr provides neutral semantics for the comparisson. + */ + + void (*cbaddr)(void); + +} panda_cb_with_context; + // END_PYPANDA_NEEDS_THIS -- do not delete this comment! #ifdef __cplusplus diff --git a/panda/include/panda/callbacks/cb-helper-impl.h b/panda/include/panda/callbacks/cb-helper-impl.h index e9f73da358b..a7f913e7268 100644 --- a/panda/include/panda/callbacks/cb-helper-impl.h +++ b/panda/include/panda/callbacks/cb-helper-impl.h @@ -19,7 +19,7 @@ void HELPER(panda_insn_exec)(target_ulong pc) { // PANDA instrumentation: before basic block panda_cb_list *plist; for(plist = panda_cbs[PANDA_CB_INSN_EXEC]; plist != NULL; plist = panda_cb_list_next(plist)) { - plist->entry.insn_exec(first_cpu, pc); + plist->entry.insn_exec(plist->context, first_cpu, pc); } } @@ -27,7 +27,7 @@ void HELPER(panda_after_insn_exec)(target_ulong pc) { // PANDA instrumentation: after basic block panda_cb_list *plist; for(plist = panda_cbs[PANDA_CB_AFTER_INSN_EXEC]; plist != NULL; plist = panda_cb_list_next(plist)) { - plist->entry.after_insn_exec(first_cpu, pc); + plist->entry.after_insn_exec(plist->context, first_cpu, pc); } } diff --git a/panda/include/panda/callbacks/cb-macros.h b/panda/include/panda/callbacks/cb-macros.h index 7d2dbfa4bbd..6c19845115b 100644 --- a/panda/include/panda/callbacks/cb-macros.h +++ b/panda/include/panda/callbacks/cb-macros.h @@ -55,8 +55,11 @@ plist != NULL; \ plist = panda_cb_list_next(plist)) { \ if (plist->enabled) \ - plist->entry. ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ + plist->entry. ENTRY_NAME(name, plist->context, EVERY_SECOND(__VA_ARGS__)); \ } \ + } \ + void panda_cb_trampoline_ ## name(void* context, COMBINE_TYPES(__VA_ARGS__)) {\ + (*(panda_cb*)context) . ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ } // Call all enabled & registered functions for this callback. Return @@ -70,9 +73,12 @@ plist != NULL; \ plist = panda_cb_list_next(plist)) { \ if (plist->enabled) \ - any_true |= plist->entry. ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ + any_true |= plist->entry. ENTRY_NAME(name, plist->context, EVERY_SECOND(__VA_ARGS__)); \ } \ return any_true; \ + } \ + bool panda_cb_trampoline_ ## name(void* context, COMBINE_TYPES(__VA_ARGS__)) {\ + return (*(panda_cb*)context) . ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ } // XXX: gcc/clang both stringify 'void' -> 'void' but 'bool' -> '_Bool' @@ -94,7 +100,45 @@ plist != NULL; \ plist = panda_cb_list_next(plist)) { \ if (plist->enabled) \ - plist->entry. ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ + plist->entry. ENTRY_NAME(name, plist->context, EVERY_SECOND(__VA_ARGS__)); \ } \ } \ + } \ + void panda_cb_trampoline_ ## name(void* context, COMBINE_TYPES(__VA_ARGS__)) {\ + (*(panda_cb*)context) . ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ } + +#define MAKE_CALLBACK_NO_ARGS_void(name_upper, name) \ + void panda_callbacks_ ## name(void) { \ + panda_cb_list *plist; \ + for (plist = panda_cbs[PANDA_CB_ ## name_upper]; \ + plist != NULL; \ + plist = panda_cb_list_next(plist)) { \ + if (plist->enabled) \ + plist->entry. ENTRY_NAME(name, plist->context); \ + } \ + } \ + void panda_cb_trampoline_ ## name(void* context) {\ + (*(panda_cb*)context) . ENTRY_NAME(name); \ + } + +#define MAKE_CALLBACK_NO_ARGS__Bool(name_upper, name) \ + bool panda_callbacks_ ## name(void) { \ + panda_cb_list *plist; \ + bool any_true = false; \ + for (plist = panda_cbs[PANDA_CB_ ## name_upper]; \ + plist != NULL; \ + plist = panda_cb_list_next(plist)) { \ + if (plist->enabled) \ + any_true |= plist->entry. ENTRY_NAME(name, plist->context); \ + } \ + return any_true; \ + } \ + bool panda_cb_trampoline_ ## name(void* context) {\ + return (*(panda_cb*)context) . ENTRY_NAME(name); \ + } + +#define _GET_CB_NAME_NO_ARGS(rettype) \ + MAKE_CALLBACK_NO_ARGS_ ## rettype + +#define MAKE_CALLBACK_NO_ARGS(rettype, ...) _GET_CB_NAME_NO_ARGS(rettype)(__VA_ARGS__) diff --git a/panda/include/panda/callbacks/cb-support.h b/panda/include/panda/callbacks/cb-support.h index 640eec14547..af894b7f4d5 100644 --- a/panda/include/panda/callbacks/cb-support.h +++ b/panda/include/panda/callbacks/cb-support.h @@ -138,4 +138,4 @@ void panda_callbacks_before_tcg_codegen(CPUState *env, TranslationBlock *tb); void panda_callbacks_start_block_exec(CPUState *env, TranslationBlock *tb); void panda_callbacks_end_block_exec(CPUState *env, TranslationBlock *tb); -void panda_install_block_callbacks(CPUState* cpu, TranslationBlock* tb); \ No newline at end of file +void panda_install_block_callbacks(CPUState* cpu, TranslationBlock* tb); diff --git a/panda/include/panda/callbacks/cb-trampolines.h b/panda/include/panda/callbacks/cb-trampolines.h new file mode 100644 index 00000000000..2151a8efe90 --- /dev/null +++ b/panda/include/panda/callbacks/cb-trampolines.h @@ -0,0 +1,83 @@ +#ifndef EXEC_ALL_H +// If this file is included from a file that doesn't define TranslationBlock (e.g., memory.c), we still need to be valid +typedef struct {} TranslationBlock; +#endif + +/*************************************************************************** + * CALLBACK TRAMPOLINES * + ***************************************************************************/ + +void panda_cb_trampoline_virt_mem_before_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size); +void panda_cb_trampoline_virt_mem_after_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); +void panda_cb_trampoline_virt_mem_before_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); +void panda_cb_trampoline_virt_mem_after_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); +void panda_cb_trampoline_phys_mem_before_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size); +void panda_cb_trampoline_phys_mem_after_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); +void panda_cb_trampoline_phys_mem_before_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); +void panda_cb_trampoline_phys_mem_after_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf); + +int panda_cb_trampoline_insn_exec(void* context, CPUState *env, target_ptr_t pc); +int panda_cb_trampoline_after_insn_exec(void* context, CPUState *env, target_ptr_t pc); +//int panda_cb_trampoline_monitor(void* context, Monitor *mon, const char *cmd); +//int panda_cb_trampoline_before_loadvm(void* context); +void panda_cb_trampoline_replay_hd_transfer(void* context, CPUState *env, uint32_t type, target_ptr_t src_addr, target_ptr_t dest_addr, size_t num_bytes); +void panda_cb_trampoline_after_machine_init(void* context, CPUState *env); +void panda_cb_trampoline_after_loadvm(void* context, CPUState *env); + +/* invoked from cpu-exec.c */ +void panda_cb_trampoline_before_block_exec(void* context, CPUState *env, TranslationBlock *tb); +void panda_cb_trampoline_after_block_exec(void* context, CPUState *env, TranslationBlock *tb, uint8_t exitCode); +void panda_cb_trampoline_before_block_translate(void* context, CPUState *env, target_ptr_t pc); +void panda_cb_trampoline_after_block_translate(void* context, CPUState *env, TranslationBlock *tb); +void panda_cb_trampoline_after_cpu_exec_enter(void* context, CPUState *env); +void panda_cb_trampoline_before_cpu_exec_exit(void* context, CPUState *env, bool ranBlock); + +/* invoked from cpu-exec.c (indirectly) */ +bool panda_cb_trampoline_before_block_exec_invalidate_opt(void* context, CPUState *env, TranslationBlock *tb); + +/* invoked from cpus.c */ +void panda_cb_trampoline_top_loop(void* context, CPUState *env); +void panda_cb_trampoline_during_machine_init(void* context, MachineState *machine); +void panda_cb_trampoline_main_loop_wait(void* context); +void panda_cb_trampoline_pre_shutdown(void* context); +bool panda_cb_trampoline_unassigned_io_read(void* context, CPUState *env, target_ptr_t pc, hwaddr addr, size_t size, uint64_t *val); +bool panda_cb_trampoline_unassigned_io_write(void* context, CPUState *env, target_ptr_t pc, hwaddr addr, size_t size, uint64_t val); +int32_t panda_cb_trampoline_before_handle_exception(void* context, CPUState *cpu, int32_t exception_index); +int32_t panda_cb_trampoline_before_handle_interrupt(void* context, CPUState *cpu, int32_t exception_index); +void panda_cb_trampoline_cbaddr(void* context); + +/* invoked from cputlb.c */ +void panda_cb_trampoline_mmio_after_read(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); +void panda_cb_trampoline_mmio_before_write(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); +//void panda_cb_trampoline_hd_read(void* context, CPUState *env); +//void panda_cb_trampoline_hd_write(void* context, CPUState *env); + +/* invoked from exec.c */ +void panda_cb_trampoline_replay_before_dma(void* context, CPUState *env, const uint8_t *buf, hwaddr addr, size_t size, bool is_write); +void panda_cb_trampoline_replay_after_dma(void* context, CPUState *env, const uint8_t *buf, hwaddr addr, size_t size, bool is_write); + +/* invoked from panda/src/rr/rr_log.c */ +void panda_cb_trampoline_replay_handle_packet(void* context, CPUState *env, uint8_t *buf, size_t size, uint8_t direction, uint64_t buf_addr_rec); +void panda_cb_trampoline_replay_net_transfer(void* context, CPUState *env, uint32_t type, uint64_t src_addr, uint64_t dest_addr, size_t num_bytes); +void panda_cb_trampoline_replay_serial_receive(void* context, CPUState *env, target_ptr_t fifo_addr, uint8_t value); +void panda_cb_trampoline_replay_serial_read(void* context, CPUState *env, target_ptr_t fifo_addr, uint32_t port_addr, uint8_t value); +void panda_cb_trampoline_replay_serial_send(void* context, CPUState *env, target_ptr_t fifo_addr, uint8_t value); +void panda_cb_trampoline_replay_serial_write(void* context, CPUState *env, target_ptr_t fifo_addr, uint32_t port_addr, uint8_t value); + +/* invoked from panda/target/ARCH/translate.c */ +bool panda_cb_trampoline_insn_translate(void* context, CPUState *env, target_ptr_t pc); +bool panda_cb_trampoline_after_insn_translate(void* context, CPUState *env, target_ptr_t pc); + +/* invoked from target/i386/helper.c */ +bool panda_cb_trampoline_asid_changed(void* context, CPUState *env, target_ptr_t oldval, target_ptr_t newval); + +/* invoked from target/i386/misc_helper.c */ +bool panda_cb_trampoline_guest_hypercall(void* context, CPUState *env); + +/* invoked from translate-all.c */ +void panda_cb_trampoline_cpu_restore_state(void* context, CPUState *env, TranslationBlock *tb); + + +void panda_cb_trampoline_before_tcg_codegen(void* context, CPUState *env, TranslationBlock *tb); +void panda_cb_trampoline_start_block_exec(void* context, CPUState *env, TranslationBlock *tb); +void panda_cb_trampoline_end_block_exec(void* context, CPUState *env, TranslationBlock *tb); diff --git a/panda/include/panda/plugin.h b/panda/include/panda/plugin.h index d001fe8aeb7..0d77fa69273 100644 --- a/panda/include/panda/plugin.h +++ b/panda/include/panda/plugin.h @@ -37,11 +37,12 @@ extern "C" { // Doubly linked list that stores a callback, along with its owner typedef struct _panda_cb_list panda_cb_list; struct _panda_cb_list { - panda_cb entry; + panda_cb_with_context entry; void *owner; panda_cb_list *next; panda_cb_list *prev; bool enabled; + void* context; }; panda_cb_list *panda_cb_list_next(panda_cb_list *plist); void panda_enable_plugin(void *plugin); @@ -53,7 +54,9 @@ typedef struct panda_plugin { void *plugin; // Handle to the plugin (for use with dlsym()) } panda_plugin; +panda_cb_with_context panda_get_cb_trampoline(panda_cb_type type); void panda_register_callback(void *plugin, panda_cb_type type, panda_cb cb); +void panda_register_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context); void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb); void panda_enable_callback(void *plugin, panda_cb_type type, panda_cb cb); void panda_unregister_callbacks(void *plugin); diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index 27f9d3d3134..5e65bf635f4 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -32,6 +32,7 @@ PANDAENDCOMMENT */ #include "panda/common.h" #include "panda/rr/rr_api.h" +#include "panda/callbacks/cb-trampolines.h" #define LIBRARY_DIR "/" TARGET_NAME "-softmmu/libpanda-" TARGET_NAME ".so" #define PLUGIN_DIR "/" TARGET_NAME "-softmmu/panda/plugins/" @@ -418,6 +419,71 @@ void *panda_get_plugin_by_name(const char *plugin_name) return NULL; } +#define CASE_CB_TRAMPOLINE(kind,name) \ + case PANDA_CB_ ## kind: \ + trampoline_cb. name = panda_cb_trampoline_ ## name; \ + break; + +panda_cb_with_context panda_get_cb_trampoline(panda_cb_type type) { + panda_cb_with_context trampoline_cb; + switch (type) { + CASE_CB_TRAMPOLINE(BEFORE_BLOCK_TRANSLATE,before_block_translate) + CASE_CB_TRAMPOLINE(AFTER_BLOCK_TRANSLATE,after_block_translate) + CASE_CB_TRAMPOLINE(BEFORE_BLOCK_EXEC_INVALIDATE_OPT,before_block_exec_invalidate_opt) + CASE_CB_TRAMPOLINE(BEFORE_TCG_CODEGEN,before_tcg_codegen) + CASE_CB_TRAMPOLINE(BEFORE_BLOCK_EXEC,before_block_exec) + CASE_CB_TRAMPOLINE(AFTER_BLOCK_EXEC,after_block_exec) + CASE_CB_TRAMPOLINE(INSN_TRANSLATE,insn_translate) + CASE_CB_TRAMPOLINE(INSN_EXEC,insn_exec) + CASE_CB_TRAMPOLINE(AFTER_INSN_TRANSLATE,after_insn_translate) + CASE_CB_TRAMPOLINE(AFTER_INSN_EXEC,after_insn_exec) + CASE_CB_TRAMPOLINE(VIRT_MEM_BEFORE_READ,virt_mem_before_read) + CASE_CB_TRAMPOLINE(VIRT_MEM_BEFORE_WRITE,virt_mem_before_write) + CASE_CB_TRAMPOLINE(PHYS_MEM_BEFORE_READ,phys_mem_before_read) + CASE_CB_TRAMPOLINE(PHYS_MEM_BEFORE_WRITE,phys_mem_before_write) + CASE_CB_TRAMPOLINE(VIRT_MEM_AFTER_READ,virt_mem_after_read) + CASE_CB_TRAMPOLINE(VIRT_MEM_AFTER_WRITE,virt_mem_after_write) + CASE_CB_TRAMPOLINE(PHYS_MEM_AFTER_READ,phys_mem_after_read) + CASE_CB_TRAMPOLINE(PHYS_MEM_AFTER_WRITE,phys_mem_after_write) + CASE_CB_TRAMPOLINE(MMIO_AFTER_READ,mmio_after_read) + CASE_CB_TRAMPOLINE(MMIO_BEFORE_WRITE,mmio_before_write) + //CASE_CB_TRAMPOLINE(HD_READ,hd_read) + //CASE_CB_TRAMPOLINE(HD_WRITE,hd_write) + CASE_CB_TRAMPOLINE(GUEST_HYPERCALL,guest_hypercall) + //CASE_CB_TRAMPOLINE(MONITOR,monitor) + CASE_CB_TRAMPOLINE(CPU_RESTORE_STATE,cpu_restore_state) + //CASE_CB_TRAMPOLINE(BEFORE_LOADVM,before_loadvm) + CASE_CB_TRAMPOLINE(ASID_CHANGED,asid_changed) + CASE_CB_TRAMPOLINE(REPLAY_HD_TRANSFER,replay_hd_transfer) + CASE_CB_TRAMPOLINE(REPLAY_NET_TRANSFER,replay_net_transfer) + CASE_CB_TRAMPOLINE(REPLAY_SERIAL_RECEIVE,replay_serial_receive) + CASE_CB_TRAMPOLINE(REPLAY_SERIAL_READ,replay_serial_read) + CASE_CB_TRAMPOLINE(REPLAY_SERIAL_SEND,replay_serial_send) + CASE_CB_TRAMPOLINE(REPLAY_SERIAL_WRITE,replay_serial_write) + CASE_CB_TRAMPOLINE(REPLAY_BEFORE_DMA,replay_before_dma) + CASE_CB_TRAMPOLINE(REPLAY_AFTER_DMA,replay_after_dma) + CASE_CB_TRAMPOLINE(REPLAY_HANDLE_PACKET,replay_handle_packet) + CASE_CB_TRAMPOLINE(AFTER_CPU_EXEC_ENTER,after_cpu_exec_enter) + CASE_CB_TRAMPOLINE(BEFORE_CPU_EXEC_EXIT,before_cpu_exec_exit) + CASE_CB_TRAMPOLINE(AFTER_MACHINE_INIT,after_machine_init) + CASE_CB_TRAMPOLINE(AFTER_LOADVM,after_loadvm) + CASE_CB_TRAMPOLINE(TOP_LOOP,top_loop) + CASE_CB_TRAMPOLINE(DURING_MACHINE_INIT,during_machine_init) + CASE_CB_TRAMPOLINE(MAIN_LOOP_WAIT,main_loop_wait) + CASE_CB_TRAMPOLINE(PRE_SHUTDOWN,pre_shutdown) + CASE_CB_TRAMPOLINE(UNASSIGNED_IO_READ,unassigned_io_read) + CASE_CB_TRAMPOLINE(UNASSIGNED_IO_WRITE,unassigned_io_write) + CASE_CB_TRAMPOLINE(BEFORE_HANDLE_EXCEPTION,before_handle_exception) + CASE_CB_TRAMPOLINE(BEFORE_HANDLE_INTERRUPT,before_handle_interrupt) + CASE_CB_TRAMPOLINE(START_BLOCK_EXEC,start_block_exec) + CASE_CB_TRAMPOLINE(END_BLOCK_EXEC,end_block_exec) + + default: assert(false); + } + + return trampoline_cb; +} + /** * @brief Adds callback to the tail of the callback list and enables it. * @@ -428,6 +494,25 @@ void *panda_get_plugin_by_name(const char *plugin_name) * an assertion error. */ void panda_register_callback(void *plugin, panda_cb_type type, panda_cb cb) +{ + panda_cb_with_context trampoline = panda_get_cb_trampoline(type); + panda_cb* cb_context = malloc(sizeof(panda_cb)); + *cb_context = cb; + + panda_register_callback_with_context(plugin, type, trampoline, cb_context); +} + +/** + * @brief Adds callback to the tail of the callback list and enables it. + * + * The order of callback registration will determine the order in which + * callbacks of the same type will be invoked. Each callback will recieve the + * context variable it was passed. + * + * @note Registering a callback function twice from the same plugin will trigger + * an assertion error. + */ +void panda_register_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context) { panda_cb_list *plist_last = NULL; @@ -1290,7 +1375,7 @@ void hmp_panda_plugin_cmd(Monitor *mon, const QDict *qdict) { panda_cb_list *plist; const char *cmd = qdict_get_try_str(qdict, "cmd"); for(plist = panda_cbs[PANDA_CB_MONITOR]; plist != NULL; plist = panda_cb_list_next(plist)) { - plist->entry.monitor(mon, cmd); + plist->entry.monitor(plist->context, mon, cmd); } } diff --git a/panda/src/cb-support.c b/panda/src/cb-support.c index 29d7a1e0672..685611b643e 100644 --- a/panda/src/cb-support.c +++ b/panda/src/cb-support.c @@ -12,6 +12,7 @@ // For each callback, use MAKE_CALLBACK or MAKE_REPLAY_ONLY_CALLBACK as defined in #include "panda/callbacks/cb-macros.h" +#include "panda/callbacks/cb-trampolines.h" #define PCB(name) panda_callbacks_ ## name @@ -166,9 +167,9 @@ MAKE_REPLAY_ONLY_CALLBACK(REPLAY_SERIAL_WRITE, replay_serial_write, CPUState*, env, target_ptr_t, fifo_addr, uint32_t, port_addr, uint8_t, value); -MAKE_CALLBACK(void, MAIN_LOOP_WAIT, main_loop_wait, void); +MAKE_CALLBACK_NO_ARGS(void, MAIN_LOOP_WAIT, main_loop_wait); -MAKE_CALLBACK(void, PRE_SHUTDOWN, pre_shutdown, void); +MAKE_CALLBACK_NO_ARGS(void, PRE_SHUTDOWN, pre_shutdown); // Non-standard callbacks below here @@ -187,6 +188,11 @@ void PCB(before_find_fast)(void) { tb_flush(first_cpu); } } + +bool panda_cb_trampoline_before_block_exec_invalidate_opt(void* context, CPUState *env, TranslationBlock *tb) { + return (*(panda_cb*)context).before_block_exec_invalidate_opt(env, tb); +} + bool PCB(after_find_fast)(CPUState *cpu, TranslationBlock *tb, bool bb_invalidate_done, bool *invalidate) { panda_cb_list *plist; @@ -195,13 +201,24 @@ bool PCB(after_find_fast)(CPUState *cpu, TranslationBlock *tb, plist != NULL; plist = panda_cb_list_next(plist)) { if (plist->enabled) *invalidate |= - plist->entry.before_block_exec_invalidate_opt(cpu, tb); + plist->entry.before_block_exec_invalidate_opt(plist->context, cpu, tb); } return true; } return false; } +int32_t panda_cb_trampoline_before_handle_exception(void* context, CPUState *cpu, int32_t exception_index) { + return (*(panda_cb*)context).before_handle_exception(cpu, exception_index); +} + +int panda_cb_trampoline_insn_exec(void* context, CPUState *env, target_ptr_t pc) { + return (*(panda_cb*)context).insn_exec(env, pc); +} + +int panda_cb_trampoline_after_insn_exec(void* context, CPUState *env, target_ptr_t pc) { + return (*(panda_cb*)context).after_insn_exec(env, pc); +} // this callback allows us to swallow exceptions // @@ -220,7 +237,7 @@ int32_t PCB(before_handle_exception)(CPUState *cpu, int32_t exception_index) { for (plist = panda_cbs[PANDA_CB_BEFORE_HANDLE_EXCEPTION]; plist != NULL; plist = panda_cb_list_next(plist)) { if (plist->enabled) { - int32_t new_e = plist->entry.before_handle_exception(cpu, exception_index); + int32_t new_e = plist->entry.before_handle_exception(plist->context, cpu, exception_index); if (!got_new_exception && new_e != exception_index) { got_new_exception = true; new_exception = new_e; @@ -234,6 +251,9 @@ int32_t PCB(before_handle_exception)(CPUState *cpu, int32_t exception_index) { return exception_index; } +int32_t panda_cb_trampoline_before_handle_interrupt(void* context, CPUState *cpu, int32_t interrupt_request) { + return (*(panda_cb*)context).before_handle_interrupt(cpu, interrupt_request); +} int32_t PCB(before_handle_interrupt)(CPUState *cpu, int32_t interrupt_request) { panda_cb_list *plist; @@ -243,7 +263,7 @@ int32_t PCB(before_handle_interrupt)(CPUState *cpu, int32_t interrupt_request) { for (plist = panda_cbs[PANDA_CB_BEFORE_HANDLE_INTERRUPT]; plist != NULL; plist = panda_cb_list_next(plist)) { if (plist->enabled) { - int32_t new_i = plist->entry.before_handle_interrupt(cpu, interrupt_request); + int32_t new_i = plist->entry.before_handle_interrupt(plist->context, cpu, interrupt_request); if (!got_new_interrupt && new_i != interrupt_request) { got_new_interrupt = true; new_interrupt = new_i; @@ -257,6 +277,22 @@ int32_t PCB(before_handle_interrupt)(CPUState *cpu, int32_t interrupt_request) { return interrupt_request; } +#define MEM_CB_TRAMPOLINES(mode) \ + void panda_cb_trampoline_ ## mode ## _mem_before_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size) { \ + (*(panda_cb*)context) . mode ## _mem_before_read(env, pc, addr, size); \ + } \ + void panda_cb_trampoline_ ## mode ## _mem_after_read(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf) { \ + (*(panda_cb*)context) . mode ## _mem_after_read(env, pc, addr, size, buf); \ + } \ + void panda_cb_trampoline_ ## mode ## _mem_before_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf) { \ + (*(panda_cb*)context) . mode ## _mem_before_write(env, pc, addr, size, buf);\ + } \ + void panda_cb_trampoline_ ## mode ## _mem_after_write(void* context, CPUState *env, target_ptr_t pc, target_ptr_t addr, size_t size, uint8_t *buf) { \ + (*(panda_cb*)context) . mode ## _mem_after_write(env, pc, addr, size, buf); \ + } + +MEM_CB_TRAMPOLINES(virt) +MEM_CB_TRAMPOLINES(phys) // These are used in softmmu_template.h. They are distinct from MAKE_CALLBACK's standard form. // ram_ptr is a possible pointer into host memory from the TLB code. Can be NULL. @@ -265,7 +301,7 @@ void PCB(mem_before_read)(CPUState *env, target_ptr_t pc, target_ptr_t addr, panda_cb_list *plist; for(plist = panda_cbs[PANDA_CB_VIRT_MEM_BEFORE_READ]; plist != NULL; plist = panda_cb_list_next(plist)) { - if (plist->enabled) plist->entry.virt_mem_before_read(env, env->panda_guest_pc, addr, + if (plist->enabled) plist->entry.virt_mem_before_read(plist->context, env, env->panda_guest_pc, addr, data_size); } if (panda_cbs[PANDA_CB_PHYS_MEM_BEFORE_READ]) { @@ -273,7 +309,7 @@ void PCB(mem_before_read)(CPUState *env, target_ptr_t pc, target_ptr_t addr, if (paddr == -1) return; for(plist = panda_cbs[PANDA_CB_PHYS_MEM_BEFORE_READ]; plist != NULL; plist = panda_cb_list_next(plist)) { - if (plist->enabled) plist->entry.phys_mem_before_read(env, env->panda_guest_pc, + if (plist->enabled) plist->entry.phys_mem_before_read(plist->context, env, env->panda_guest_pc, paddr, data_size); } } @@ -286,7 +322,7 @@ void PCB(mem_after_read)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for(plist = panda_cbs[PANDA_CB_VIRT_MEM_AFTER_READ]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &result as the last cb arg doesn't make much sense. */ - if (plist->enabled) plist->entry.virt_mem_after_read(env, env->panda_guest_pc, addr, + if (plist->enabled) plist->entry.virt_mem_after_read(plist->context, env, env->panda_guest_pc, addr, data_size, (uint8_t *)&result); } if (panda_cbs[PANDA_CB_PHYS_MEM_AFTER_READ]) { @@ -295,7 +331,7 @@ void PCB(mem_after_read)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for(plist = panda_cbs[PANDA_CB_PHYS_MEM_AFTER_READ]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &result as the last cb arg doesn't make much sense. */ - if (plist->enabled) plist->entry.phys_mem_after_read(env, env->panda_guest_pc, paddr, + if (plist->enabled) plist->entry.phys_mem_after_read(plist->context, env, env->panda_guest_pc, paddr, data_size, (uint8_t *)&result); } } @@ -308,7 +344,7 @@ void PCB(mem_before_write)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for(plist = panda_cbs[PANDA_CB_VIRT_MEM_BEFORE_WRITE]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &val as the last arg doesn't make much sense. */ - if (plist->enabled) plist->entry.virt_mem_before_write(env, env->panda_guest_pc, addr, + if (plist->enabled) plist->entry.virt_mem_before_write(plist->context, env, env->panda_guest_pc, addr, data_size, (uint8_t *)&val); } if (panda_cbs[PANDA_CB_PHYS_MEM_BEFORE_WRITE]) { @@ -317,7 +353,7 @@ void PCB(mem_before_write)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for(plist = panda_cbs[PANDA_CB_PHYS_MEM_BEFORE_WRITE]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &val as the last cb arg doesn't make much sense. */ - if (plist->enabled) plist->entry.phys_mem_before_write(env, env->panda_guest_pc, paddr, + if (plist->enabled) plist->entry.phys_mem_before_write(plist->context, env, env->panda_guest_pc, paddr, data_size, (uint8_t *)&val); } } @@ -330,7 +366,7 @@ void PCB(mem_after_write)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for (plist = panda_cbs[PANDA_CB_VIRT_MEM_AFTER_WRITE]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &val as the last cb arg doesn't make much sense. */ - if (plist->enabled) plist->entry.virt_mem_after_write(env, env->panda_guest_pc, addr, + if (plist->enabled) plist->entry.virt_mem_after_write(plist->context, env, env->panda_guest_pc, addr, data_size, (uint8_t *)&val); } if (panda_cbs[PANDA_CB_PHYS_MEM_AFTER_WRITE]) { @@ -339,7 +375,7 @@ void PCB(mem_after_write)(CPUState *env, target_ptr_t pc, target_ptr_t addr, for (plist = panda_cbs[PANDA_CB_PHYS_MEM_AFTER_WRITE]; plist != NULL; plist = panda_cb_list_next(plist)) { /* mstamat: Passing &val as the last cb arg doesn't make much sense. */ - if (plist->enabled) plist->entry.phys_mem_after_write(env, env->panda_guest_pc, paddr, + if (plist->enabled) plist->entry.phys_mem_after_write(plist->context, env, env->panda_guest_pc, paddr, data_size, (uint8_t *)&val); } } From b6beeedb87990d9624a1ec34a463177e27c0d232 Mon Sep 17 00:00:00 2001 From: jamcleod Date: Fri, 15 Oct 2021 01:24:58 -0400 Subject: [PATCH 2/5] Fix callback context not actually being set --- panda/src/callbacks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index 5e65bf635f4..b2549bdc388 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -520,6 +520,7 @@ void panda_register_callback_with_context(void *plugin, panda_cb_type type, pand new_list->entry = cb; new_list->owner = plugin; new_list->enabled = true; + new_list->context = context; assert(type < PANDA_CB_LAST); if (panda_cbs[type] != NULL) { From 0f58219fabb5b0e869ccd48fcfc3a1c273f02d69 Mon Sep 17 00:00:00 2001 From: jamcleod Date: Fri, 15 Oct 2021 01:33:47 -0400 Subject: [PATCH 3/5] Fix disabling callbacks using trampolines --- panda/src/callbacks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index b2549bdc388..1500f22487b 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -569,9 +569,11 @@ void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb) bool found = false; assert(type < PANDA_CB_LAST); if (panda_cbs[type] != NULL) { + panda_cb_with_context trampoline = panda_get_cb_trampoline(type); for (panda_cb_list *plist = panda_cbs[type]; plist != NULL; plist = plist->next) { - if (plist->owner == plugin && (plist->entry.cbaddr) == cb.cbaddr) { + if (plist->owner == plugin && (((plist->entry.cbaddr) == cb.cbaddr) + || ((plist->entry.cbaddr) == trampoline.cbaddr))) { found = true; plist->enabled = false; From e1a7088d3fdeb2ba46d4fe27f5624c06d9955f37 Mon Sep 17 00:00:00 2001 From: jamcleod Date: Fri, 15 Oct 2021 13:44:37 -0400 Subject: [PATCH 4/5] Fix enabling/disabling of callbacks with context --- panda/include/panda/plugin.h | 2 ++ panda/src/callbacks.c | 66 +++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/panda/include/panda/plugin.h b/panda/include/panda/plugin.h index 0d77fa69273..83b186805ea 100644 --- a/panda/include/panda/plugin.h +++ b/panda/include/panda/plugin.h @@ -59,6 +59,8 @@ void panda_register_callback(void *plugin, panda_cb_type type, panda_cb cb); void panda_register_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context); void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb); void panda_enable_callback(void *plugin, panda_cb_type type, panda_cb cb); +void panda_disable_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context); +void panda_enable_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context); void panda_unregister_callbacks(void *plugin); bool panda_load_plugin(const char *filename, const char *plugin_name); bool _panda_load_plugin(const char *filename, const char *plugin_name, bool library_mode); diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index 1500f22487b..e9408e5c9c1 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -528,7 +528,8 @@ void panda_register_callback_with_context(void *plugin, panda_cb_type type, pand plist = plist->next) { // the same plugin can register the same callback function only once assert(!(plist->owner == plugin && - (plist->entry.cbaddr) == cb.cbaddr)); + (plist->entry.cbaddr) == cb.cbaddr && + plist->context == context)); plist_last = plist; } plist_last->next = new_list; @@ -555,6 +556,9 @@ bool panda_is_callback_enabled(void *plugin, panda_cb_type type, panda_cb cb) { return false; } +#define TRAMP_CTXT(context) \ + (*(panda_cb*)context).cbaddr + /** * @brief Disables the execution of the specified callback. * @@ -564,7 +568,21 @@ bool panda_is_callback_enabled(void *plugin, panda_cb_type type, panda_cb cb) { * * @note Disabling an unregistered callback will trigger an assertion error. */ -void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb) +void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb) { + panda_cb_with_context trampoline = panda_get_cb_trampoline(type); + panda_disable_callback_with_context(plugin, type, trampoline, &cb); +} + +/** + * @brief Disables the execution of the specified callback. + * + * This is done by setting the `enabled` flag to `false`. The callback remains + * in the callback list, so when it is enabled again it will execute in the same + * relative order. + * + * @note Disabling an unregistered callback will trigger an assertion error. + */ +void panda_disable_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context) { bool found = false; assert(type < PANDA_CB_LAST); @@ -572,8 +590,15 @@ void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb) panda_cb_with_context trampoline = panda_get_cb_trampoline(type); for (panda_cb_list *plist = panda_cbs[type]; plist != NULL; plist = plist->next) { - if (plist->owner == plugin && (((plist->entry.cbaddr) == cb.cbaddr) - || ((plist->entry.cbaddr) == trampoline.cbaddr))) { + if (plist->owner == plugin && + ((((plist->entry.cbaddr) == cb.cbaddr) && plist->context == context) || + ( + // if and only if it's a trampoline, it's safe to dereference the + // context in order to do an equality check + plist->entry.cbaddr == trampoline.cbaddr + && TRAMP_CTXT(context) == TRAMP_CTXT(plist->context) + )) + ) { found = true; plist->enabled = false; @@ -596,14 +621,37 @@ void panda_disable_callback(void *plugin, panda_cb_type type, panda_cb cb) * * @note Enabling an unregistered callback will trigger an assertion error. */ -void panda_enable_callback(void *plugin, panda_cb_type type, panda_cb cb) +void panda_enable_callback(void *plugin, panda_cb_type type, panda_cb cb) { + panda_cb_with_context trampoline = panda_get_cb_trampoline(type); + panda_enable_callback_with_context(plugin, type, trampoline, &cb); +} + +/** + * @brief Enables the execution of the specified callback. + * + * This is done by setting the `enabled` flag to `true`. After enabling the + * callback, it will execute in the same relative order as before having it + * disabled. + * + * @note Enabling an unregistered callback will trigger an assertion error. + */ +void panda_enable_callback_with_context(void *plugin, panda_cb_type type, panda_cb_with_context cb, void* context) { bool found = false; - assert(type < PANDA_CB_LAST); if (panda_cbs[type] != NULL) { - for (panda_cb_list *plist = panda_cbs[type]; plist != NULL; - plist = plist->next) { - if (plist->owner == plugin && (plist->entry.cbaddr) == cb.cbaddr) { + panda_cb_with_context trampoline = panda_get_cb_trampoline(type); + for (panda_cb_list *plist = panda_cbs[type]; plist != NULL; plist = plist->next) + { + if (plist->owner == plugin && (( + (plist->entry.cbaddr) == cb.cbaddr && plist->context == context + ) || + ( + // if and only if it's a trampoline, it's safe to dereference the + // context in order to do an equality check + plist->entry.cbaddr == trampoline.cbaddr + && TRAMP_CTXT(plist->context) == TRAMP_CTXT(context) + )) + ) { found = true; plist->enabled = true; From 11e34d03b94b4f8725f4b8bb1a599e3409051f99 Mon Sep 17 00:00:00 2001 From: jamcleod Date: Fri, 15 Oct 2021 14:34:42 -0400 Subject: [PATCH 5/5] Add trampolines for unused callbacks --- panda/include/panda/callbacks/cb-macros.h | 15 +++++++++++++++ panda/include/panda/callbacks/cb-trampolines.h | 6 +++--- panda/src/callbacks.c | 7 ++++--- panda/src/cb-support.c | 5 +++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/panda/include/panda/callbacks/cb-macros.h b/panda/include/panda/callbacks/cb-macros.h index 6c19845115b..5b3cb75a3bc 100644 --- a/panda/include/panda/callbacks/cb-macros.h +++ b/panda/include/panda/callbacks/cb-macros.h @@ -62,6 +62,21 @@ (*(panda_cb*)context) . ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ } +#define MAKE_CALLBACK_int(name_upper, name, ...) \ + int panda_callbacks_ ## name(COMBINE_TYPES(__VA_ARGS__)) { \ + panda_cb_list *plist; \ + for (plist = panda_cbs[PANDA_CB_ ## name_upper]; \ + plist != NULL; \ + plist = panda_cb_list_next(plist)) { \ + if (plist->enabled) \ + plist->entry. ENTRY_NAME(name, plist->context, EVERY_SECOND(__VA_ARGS__)); \ + } \ + return 0; \ + } \ + int panda_cb_trampoline_ ## name(void* context, COMBINE_TYPES(__VA_ARGS__)) {\ + return (*(panda_cb*)context) . ENTRY_NAME(name, EVERY_SECOND(__VA_ARGS__)); \ + } + // Call all enabled & registered functions for this callback. Return // all results together OR'd together. // XXX: double underscore in name is intentional diff --git a/panda/include/panda/callbacks/cb-trampolines.h b/panda/include/panda/callbacks/cb-trampolines.h index 2151a8efe90..f13ca5be3a3 100644 --- a/panda/include/panda/callbacks/cb-trampolines.h +++ b/panda/include/panda/callbacks/cb-trampolines.h @@ -18,7 +18,7 @@ void panda_cb_trampoline_phys_mem_after_write(void* context, CPUState *env, targ int panda_cb_trampoline_insn_exec(void* context, CPUState *env, target_ptr_t pc); int panda_cb_trampoline_after_insn_exec(void* context, CPUState *env, target_ptr_t pc); -//int panda_cb_trampoline_monitor(void* context, Monitor *mon, const char *cmd); +int panda_cb_trampoline_monitor(void* context, Monitor *mon, const char *cmd); //int panda_cb_trampoline_before_loadvm(void* context); void panda_cb_trampoline_replay_hd_transfer(void* context, CPUState *env, uint32_t type, target_ptr_t src_addr, target_ptr_t dest_addr, size_t num_bytes); void panda_cb_trampoline_after_machine_init(void* context, CPUState *env); @@ -49,8 +49,8 @@ void panda_cb_trampoline_cbaddr(void* context); /* invoked from cputlb.c */ void panda_cb_trampoline_mmio_after_read(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); void panda_cb_trampoline_mmio_before_write(void* context, CPUState *env, target_ptr_t physaddr, target_ptr_t vaddr, size_t size, uint64_t *val); -//void panda_cb_trampoline_hd_read(void* context, CPUState *env); -//void panda_cb_trampoline_hd_write(void* context, CPUState *env); +void panda_cb_trampoline_hd_read(void* context, CPUState *env); +void panda_cb_trampoline_hd_write(void* context, CPUState *env); /* invoked from exec.c */ void panda_cb_trampoline_replay_before_dma(void* context, CPUState *env, const uint8_t *buf, hwaddr addr, size_t size, bool is_write); diff --git a/panda/src/callbacks.c b/panda/src/callbacks.c index e9408e5c9c1..e7198a10d6f 100644 --- a/panda/src/callbacks.c +++ b/panda/src/callbacks.c @@ -447,11 +447,12 @@ panda_cb_with_context panda_get_cb_trampoline(panda_cb_type type) { CASE_CB_TRAMPOLINE(PHYS_MEM_AFTER_WRITE,phys_mem_after_write) CASE_CB_TRAMPOLINE(MMIO_AFTER_READ,mmio_after_read) CASE_CB_TRAMPOLINE(MMIO_BEFORE_WRITE,mmio_before_write) - //CASE_CB_TRAMPOLINE(HD_READ,hd_read) - //CASE_CB_TRAMPOLINE(HD_WRITE,hd_write) + CASE_CB_TRAMPOLINE(HD_READ,hd_read) + CASE_CB_TRAMPOLINE(HD_WRITE,hd_write) CASE_CB_TRAMPOLINE(GUEST_HYPERCALL,guest_hypercall) - //CASE_CB_TRAMPOLINE(MONITOR,monitor) + CASE_CB_TRAMPOLINE(MONITOR,monitor) CASE_CB_TRAMPOLINE(CPU_RESTORE_STATE,cpu_restore_state) + //CASE_CB_TRAMPOLINE(BEFORE_LOADVM,before_loadvm) CASE_CB_TRAMPOLINE(ASID_CHANGED,asid_changed) CASE_CB_TRAMPOLINE(REPLAY_HD_TRANSFER,replay_hd_transfer) diff --git a/panda/src/cb-support.c b/panda/src/cb-support.c index 685611b643e..781cd7fd9ab 100644 --- a/panda/src/cb-support.c +++ b/panda/src/cb-support.c @@ -81,6 +81,11 @@ MAKE_CALLBACK(void, START_BLOCK_EXEC, start_block_exec, MAKE_CALLBACK(void, END_BLOCK_EXEC, end_block_exec, CPUState*, env, TranslationBlock*, tb) +// these aren't used +MAKE_CALLBACK(void, HD_READ, hd_read, CPUState*, env); +MAKE_CALLBACK(void, HD_WRITE, hd_write, CPUState*, env); +MAKE_CALLBACK(int, MONITOR, monitor, Monitor*, mon, const char*, cmd); + // Helper - get a physical address static inline hwaddr get_paddr(CPUState *cpu, target_ptr_t addr, void *ram_ptr) { if (!ram_ptr) {