| /* ********************************************************** |
| * Copyright (c) 2010-2023 Google, Inc. All rights reserved. |
| * Copyright (c) 2002-2010 VMware, Inc. All rights reserved. |
| * **********************************************************/ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * * Neither the name of VMware, Inc. nor the names of its contributors may be |
| * used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| */ |
| |
| /* Copyright (c) 2003-2007 Determina Corp. */ |
| /* Copyright (c) 2002-2003 Massachusetts Institute of Technology */ |
| /* Copyright (c) 2002 Hewlett-Packard Company */ |
| |
| #ifndef _DR_EVENTS_H_ |
| #define _DR_EVENTS_H_ 1 |
| |
| #include "dr_config.h" |
| |
| /** |
| * @file dr_events.h |
| * @brief Event callback registration routines. |
| */ |
| |
| /************************************************** |
| * ROUTINES TO REGISTER EVENT CALLBACKS |
| */ |
| |
| DR_API |
| /** |
| * Registers a callback function for the process exit event. DR calls \p |
| * func when the process exits. By default, the process exit event will be |
| * executed with only a single live thread. dr_set_process_exit_behavior() |
| * can provide superior exit performance for clients that have flexible |
| * exit event requirements. |
| * |
| * On Linux, SYS_execve does NOT result in an exit event, but it WILL |
| * result in the client library being reloaded and its dr_client_main() |
| * routine being called. |
| */ |
| void |
| dr_register_exit_event(void (*func)(void)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the process exit event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_exit_event(void (*func)(void)); |
| |
| DR_API |
| /** |
| * Registers a function which is called after all other threads have been taken over |
| * during a process attach event, whether externally triggered or internally triggered |
| * (via dr_app_start() or related functions). If this process instance was not |
| * initiated by an attach or takeover methodology where multiple application threads may |
| * exist at the time of takeover (such as a process newly created on Linux), this |
| * registration function returns false. |
| * |
| * The attach methodology operates in a staggered fashion, with each thread being taken |
| * over and executed under DR control in turn. If the application has many threads, |
| * threads taken over early in this process may execute substantial amounts of |
| * instrumented code before the threads taken over last start executing instrumented |
| * code. The purpose of this event is to provide a single control point where all |
| * threads are known to be under DR control and running instrumented code. |
| */ |
| bool |
| dr_register_post_attach_event(void (*func)(void)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the post-attach event (see |
| * dr_register_post_attach_event()). \return true if unregistration is successful and |
| * false if it is not (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_post_attach_event(void (*func)(void)); |
| |
| DR_API |
| /** |
| * Registers a function which is called at the start of a full detach of DR from the |
| * current process, whether externally triggered or internally triggered (via |
| * dr_app_stop_and_cleanup() or related functions), as well as at the start of DR |
| * sending all threads native but not cleaning up its own state (through dr_app_stop()). |
| * |
| * The detach methodology operates in a staggered fashion, with each thread being |
| * returned to native control in turn. If the application has many threads, threads |
| * detached late in this process may execute substantial amounts of instrumented code |
| * before the full detach process is complete, while threads detached early are running |
| * natively. The purpose of this event is to provide a single final control point where |
| * all threads are known to be under DR control and running instrumented code. The exit |
| * event (see dr_register_exit_event()) is not called until after all other threads have |
| * been detached. |
| */ |
| void |
| dr_register_pre_detach_event(void (*func)(void)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the post-attach event (see |
| * dr_register_pre_detach_event()). \return true if unregistration is successful and |
| * false if it is not (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_pre_detach_event(void (*func)(void)); |
| |
| /** |
| * Flags controlling the behavior of basic blocks and traces when emitted |
| * into the code cache. These flags are bitmasks that can be combined by |
| * or-ing together. For multiple clients, the flags returned by each |
| * client are or-ed together. |
| */ |
| typedef enum { |
| /** Emit as normal. */ |
| DR_EMIT_DEFAULT = 0, |
| /** |
| * Store translation information at emit time rather than calling |
| * the basic block or trace event later to recreate the |
| * information. Note that even if a standalone basic block has |
| * stored translations, if when it is added to a trace it does not |
| * request storage (and the trace callback also does not request |
| * storage) then the basic block callback may still be called to |
| * translate for the trace. |
| * |
| * \sa #dr_register_bb_event() |
| */ |
| DR_EMIT_STORE_TRANSLATIONS = 0x01, |
| /** |
| * Only valid when applied to a basic block. Indicates that the |
| * block is eligible for persisting to a persistent code cache |
| * file on disk. By default, no blocks are eligible, as tools |
| * must take care in order to properly support persistence. |
| * Note that the block is not guaranteed to be persisted if |
| * it contains complex features that prevent DR from |
| * easily persisting it. |
| */ |
| DR_EMIT_PERSISTABLE = 0x02, |
| /** |
| * Only valid when applied to a basic block. Indicates that the |
| * block must terminate a trace. Normally this should be set when |
| * an abnormal exit is used from the block that is incompatible with |
| * trace building's attempt to inline the continuation from the block |
| * to its successor. Note that invoking dr_redirect_execution() from a |
| * clean call called from a block aborts trace building and thus this |
| * flag need not be set for that scenario. |
| */ |
| DR_EMIT_MUST_END_TRACE = 0x04, |
| /** |
| * Requests that DR relinquish control of the current thread and |
| * let it run natively until the client indicates that DR should |
| * take over again. While native, on Windows, currently only the |
| * thread init event (dr_register_thread_init_event()) will be |
| * raised, and nothing on Linux: no events will occur in the |
| * native thread. On Windows, DR tries to monitor any actions a |
| * native thread might take that affect correct execution from the |
| * code cache, but running natively carries risks. Consider this |
| * feature experimental, particularly on Linux. |
| */ |
| DR_EMIT_GO_NATIVE = 0x08, |
| } dr_emit_flags_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the basic block event. DR calls |
| * \p func before inserting a new basic block into the code cache. |
| * When adding a basic block to a new trace, DR calls \p func again |
| * with \p for_trace set to true, giving the client the opportunity to |
| * keep its same instrumentation in the trace, or to change it. The |
| * original basic block's instrumentation is unchanged by whatever |
| * action is taken in the \p for_trace call. |
| * |
| * DR constructs <em>dynamic basic blocks</em>, which are distinct |
| * from a compiler's classic basic blocks. DR does not know all entry |
| * points ahead of time, and will end up duplicating the tail of a |
| * basic block if a later entry point is discovered that targets the |
| * middle of a block created earlier, or if a later entry point |
| * targets straight-line code that falls through into code already |
| * present in a block. |
| * |
| * DR may call \p func again if it needs to translate from code cache |
| * addresses back to application addresses, which happens on faulting |
| * instructions as well as in certain situations involving suspended |
| * threads or forcibly relocated threads. The \p translating |
| * parameter distinguishes the two types of calls and is further |
| * explained below. |
| * |
| * - \p drcontext is a pointer to the input program's machine context. |
| * Clients should not inspect or modify the context; it is provided as |
| * an opaque pointer (i.e., <tt>void *</tt>) to be passed to API |
| * routines that require access to this internal data. |
| * drcontext is specific to the current thread, but in normal |
| * configurations the basic block being created is thread-shared: thus, |
| * when allocating data structures with the same lifetime as the |
| * basic block, usually global heap (#dr_global_alloc()) is a better |
| * choice than heap tied to the thread that happened to first create |
| * the basic block (#dr_thread_alloc()). Thread-private heap is fine |
| * for temporary structures such as instr_t and instrlist_t. |
| * |
| * - \p tag is a unique identifier for the basic block fragment. |
| * Use dr_fragment_app_pc() to translate it to an application address. |
| * - \p bb is a pointer to the list of instructions that comprise the |
| * basic block. Clients can examine, manipulate, or completely |
| * replace the instructions in the list. |
| * |
| * - \p translating indicates whether this callback is for basic block |
| * creation (false) or is for address translation (true). This is |
| * further explained below. |
| * |
| * The callback function should return a #dr_emit_flags_t flag. |
| * |
| * The user is free to inspect and modify the block before it |
| * executes, but must adhere to the following restrictions: |
| * - If there is more than one application branch, only the last can be |
| * conditional. |
| * - An application conditional branch must be the final |
| * instruction in the block. |
| * - An application direct call must be the final |
| * instruction in the block unless it is inserted by DR for elision and the |
| * subsequent instructions are the callee. |
| * - There can only be one indirect branch (call, jump, or return) in |
| * a basic block, and it must be the final instruction in the |
| * block. |
| * - There can only be one far branch (call, jump, or return) in |
| * a basic block, and it must be the final instruction in the |
| * block. |
| * - The AArch64 instruction ISB must be the final instruction in the |
| * block. |
| * - The exit control-flow of a block ending in a system call or |
| * int instruction cannot be changed, nor can instructions be inserted |
| * after the system call or int instruction itself, unless |
| * the system call or int instruction is removed entirely. |
| * - The number of an interrupt cannot be changed. (Note that the |
| * parameter to a system call, normally kept in the eax register, can |
| * be freely changed in a basic block: but not in a trace.) |
| * - A system call or interrupt instruction can only be added |
| * if it satisfies the above constraints: i.e., if it is the final |
| * instruction in the block and the only system call or interrupt. |
| * - Any AArch64 #OP_isb instruction must be the last instruction |
| * in its block. |
| * - All IT blocks must be legal. For example, application instructions |
| * inside an IT block cannot be removed or added to without also |
| * updating the OP_it instruction itself. Clients can use |
| * the combination of dr_remove_it_instrs() and dr_insert_it_instrs() |
| * to more easily manage IT blocks while maintaining the simplicity |
| * of examining individual instructions in isolation. |
| * - The block's application source code (as indicated by the |
| * translation targets, set by #instr_set_translation()) must remain |
| * within the original bounds of the block (the one exception to this |
| * is that a jump can translate to its target). Otherwise, DR's cache |
| * consistency algorithms cannot guarantee to properly invalidate the |
| * block if the source application code is modified. To send control |
| * to other application code regions, truncate the block and use a |
| * direct jump to target the desired address, which will then |
| * materialize in the subsequent block, rather than embedding the |
| * desired instructions in this block. |
| * - There is a limit on the size of a basic block in the code cache. |
| * DR performs its own modifications, especially on memory writes for |
| * cache consistency of self-modifying (or false sharing) code |
| * regions. If an assert fires in debug build indicating a limit was |
| * reached, either truncate blocks or use the -max_bb_instrs runtime |
| * option to ask DR to make them smaller. |
| * |
| * To support transparent fault handling, DR must translate a fault in the |
| * code cache into a fault at the corresponding application address. DR |
| * must also be able to translate when a suspended thread is examined by |
| * the application or by DR itself for internal synchronization purposes. |
| * If the client is only adding observational instrumentation (i.e., meta |
| * instructions: see #instr_set_meta()) (which should not fault) and |
| * is not modifying, reordering, or removing application instructions, |
| * these details can be ignored. In that case the client should return |
| * #DR_EMIT_DEFAULT and set up its basic block callback to be deterministic |
| * and idempotent. If the client is performing modifications, then in |
| * order for DR to properly translate a code cache address the client must |
| * use #instr_set_translation() in the basic block creation callback to set |
| * the corresponding application address (the address that should be |
| * presented to the application as the faulting address, or the address |
| * that should be restarted after a suspend) for each modified instruction |
| * and each added application instruction (see #instr_set_app()). |
| * |
| * There are two methods for using the translated addresses: |
| * |
| * -# Return #DR_EMIT_STORE_TRANSLATIONS from the basic block creation |
| * callback. DR will then store the translation addresses and use |
| * the stored information on a fault. The basic block callback for |
| * \p tag will not be called with \p translating set to true. Note |
| * that unless #DR_EMIT_STORE_TRANSLATIONS is also returned for \p |
| * for_trace calls (or #DR_EMIT_STORE_TRANSLATIONS is returned in |
| * the trace callback), each constituent block comprising the trace |
| * will need to be re-created with both \p for_trace and \p |
| * translating set to true. Storing translations uses additional |
| * memory that can be significant: up to 20% in some cases, as it |
| * prevents DR from using its simple data structures and forces it |
| * to fall back to its complex, corner-case design. This is why DR |
| * does not store all translations by default. |
| * -# Return #DR_EMIT_DEFAULT from the basic block creation callback. |
| * DR will then call the callback again during fault translation |
| * with \p translating set to true. All modifications to \p bb |
| * that were performed on the creation callback must be repeated on |
| * the translating callback. This option is only possible when |
| * basic block modifications are deterministic and idempotent, but |
| * it saves memory. Naturally, global state changes triggered by |
| * block creation should be wrapped in checks for \p translating |
| * being false. Even in this case, #instr_set_translation() should |
| * be called for application instructions even when \p translating is |
| * false, as DR may decide to store the translations at creation |
| * time for reasons of its own. |
| * |
| * Furthermore, if the client's modifications change any part of the |
| * machine state besides the program counter, the client should use |
| * #dr_register_restore_state_event() or |
| * #dr_register_restore_state_ex_event() to restore the registers and |
| * application memory to their original application values. |
| * |
| * For meta instructions that do not reference application memory |
| * (i.e., they should not fault), leave the translation field as NULL. |
| * A NULL value instructs DR to use the subsequent application |
| * instruction's translation as the application address, and to fail |
| * when translating the full state. Since the full state will only be |
| * needed when relocating a thread (as stated, there will not be a |
| * fault here), failure indicates that this is not a valid relocation |
| * point, and DR's thread synchronization scheme will use another |
| * spot. If the translation field is set to a non-NULL value, the |
| * client should be willing to also restore the rest of the machine |
| * state at that point (restore spilled registers, etc.) via |
| * #dr_register_restore_state_event() or |
| * #dr_register_restore_state_ex_event(). This is necessary for meta |
| * instructions that reference application memory. DR takes care of |
| * such potentially-faulting instructions added by its own API |
| * routines (#dr_insert_clean_call() arguments that reference |
| * application data, #dr_insert_mbr_instrumentation()'s read of |
| * application indirect branch data, etc.) |
| * |
| * \note In order to present a more straightforward code stream to clients, |
| * this release of DR disables several internal optimizations. As a result, |
| * some applications may see a performance degradation. Applications making |
| * heavy use of system calls are the most likely to be affected. |
| * Future releases may allow clients some control over performance versus |
| * visibility. The \ref op_speed "-opt_speed" option can regain some |
| * of this performance at the cost of more complex basic blocks that |
| * cross control transfers. |
| * |
| * \note If multiple clients are present, the instruction list for a |
| * basic block passed to earlier-registered clients will contain the |
| * instrumentation and modifications put in place by later-registered |
| * clients. |
| * |
| * \note Basic blocks can be deleted due to hitting capacity limits or |
| * cache consistency events (when the source application code of a |
| * basic block is modified). In that case, the client will see a new |
| * basic block callback if the block is then executed again after |
| * deletion. The deletion event (#dr_register_delete_event()) will be |
| * raised at deletion time. |
| * |
| * \note If the -thread_private runtime option is specified, clients |
| * should expect to see duplicate tags for separate threads, albeit |
| * with different dcrcontext values. Additionally, DR employs a |
| * cache-sizing algorithm for thread private operation that |
| * proactively deletes fragments. Even with thread-shared caches |
| * enabled, however, certain situations cause DR to emit |
| * thread-private basic blocks (e.g., self-modifying code). In this |
| * case, clients should be prepared to see duplicate tags without an |
| * intermediate deletion. |
| * |
| * \note A client can change the control flow of the application by |
| * changing the control transfer instruction at end of the basic block. |
| * If a basic block is ended with a non-control transfer instruction, |
| * an application jump instruction can be inserted. |
| * If a basic block is ended with a conditional branch, |
| * \p instrlist_set_fall_through_target can be used to change the |
| * fall-through target. |
| * If a basic block is ended with a call instruction, |
| * \p instrlist_set_return_target can be used to change the return |
| * target of the call. |
| */ |
| void dr_register_bb_event(dr_emit_flags_t (*func)(void *drcontext, void *tag, |
| instrlist_t *bb, bool for_trace, |
| bool translating)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the basic block event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| * |
| * \note We do not recommend unregistering for the basic block event |
| * unless it aways returned #DR_EMIT_STORE_TRANSLATIONS (including |
| * when \p for_trace is true, or if the client has a trace creation |
| * callback that returns #DR_EMIT_STORE_TRANSLATIONS). Unregistering |
| * can prevent proper state translation on a later fault or other |
| * translation event for this basic block or for a trace that includes |
| * this basic block. Instead of unregistering, turn the event |
| * callback into a nop. |
| */ |
| bool dr_unregister_bb_event(dr_emit_flags_t (*func)(void *drcontext, void *tag, |
| instrlist_t *bb, bool for_trace, |
| bool translating)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the trace event. DR calls \p func |
| * before inserting a new trace into the code cache. DR may call \p func |
| * again if it needs to translate from code cache addresses back to |
| * application addresses, which happens on faulting instructions as well as |
| * in certain situations involving suspended threads or forcibly relocated |
| * threads. The \p translating parameter distinguishes the two types of |
| * calls and behaves identically to the same parameter in the basic |
| * block callback: see #dr_register_bb_event() for further details. |
| * |
| * Traces are not built if the -disable_traces runtime option |
| * is specified. |
| * |
| * - \p drcontext is a pointer to the input program's machine context. |
| * Clients should not inspect or modify the context; it is provided as |
| * an opaque pointer (i.e., <tt>void *</tt>) to be passed to API |
| * routines that require access to this internal data. |
| * - \p tag is a unique identifier for the trace fragment. |
| * - \p trace is a pointer to the list of instructions that comprise the |
| * trace. |
| * - \p translating indicates whether this callback is for trace creation |
| * (false) or is for fault address recreation (true). This is further |
| * explained below. |
| * |
| * The callback function should return a #dr_emit_flags_t flag. |
| * |
| * The user is free to inspect and modify the non-control-flow |
| * instructions in the trace before it |
| * executes, with certain restrictions |
| * that include those for basic blocks (see dr_register_bb_event()). |
| * Additional restrictions unique to traces also apply: |
| * - The sequence of blocks composing the trace cannot be changed once |
| * the trace is created. Instead, modify the component blocks by |
| * changing the block continuation addresses in the basic block callbacks |
| * (called with \p for_trace set to true) as the trace is being built. |
| * - The (application) control flow instruction (if any) terminating each |
| * component block cannot be changed. |
| * - Application control flow instructions cannot be added. |
| * - The parameter to a system call, normally kept in the eax register, |
| * cannot be changed. |
| * - A system call or interrupt instruction cannot be added. |
| * - If both a floating-point state save instruction (fnstenv, fnsave, |
| * fxsave, xsave, or xsaveopt) and a prior regular floating-point |
| * instruction are present, the regular instruction cannot be |
| * removed. |
| * |
| * If hitting a size limit due to extensive instrumentation, reduce |
| * the -max_trace_bbs option to start with a smaller trace. |
| * |
| * The basic block restrictions on modifying application source code |
| * apply to traces as well. If the user wishes to change which basic |
| * blocks comprise the trace, either the |
| * #dr_register_end_trace_event() should be used or the \p for_trace |
| * basic block callbacks should modify their continuation addresses |
| * via direct jumps. |
| * |
| * All of the comments for #dr_register_bb_event() regarding |
| * transparent fault handling and state translation apply to the trace |
| * callback as well. Please read those comments carefully. |
| * |
| * \note As each basic block is added to a new trace, the basic block |
| * callback (see #dr_register_bb_event()) is called with its \p |
| * for_trace parameter set to true. In order to preserve basic block |
| * instrumentation inside of traces, a client need only act |
| * identically with respect to the \p for_trace parameter; it can |
| * ignore the trace event if its goal is to place instrumentation |
| * on all code. |
| * |
| * \note Certain control flow modifications applied to a basic block |
| * can prevent it from becoming part of a trace: e.g., adding |
| * additional application control transfers. |
| * |
| * \note If multiple clients are present, the instruction list for a |
| * trace passed to earlier-registered clients will contain the |
| * instrumentation and modifications put in place by later-registered |
| * clients; similarly for each constituent basic block. |
| * |
| * \note Traces can be deleted due to hitting capacity limits or cache |
| * consistency events (when the source application code of a trace is |
| * modified). In that case, the client will see a new trace callback |
| * if a new trace containing that code is created again after |
| * deletion. The deletion event (#dr_register_delete_event()) will be |
| * raised at deletion time. |
| */ |
| void dr_register_trace_event(dr_emit_flags_t (*func)(void *drcontext, void *tag, |
| instrlist_t *trace, |
| bool translating)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the trace event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| * |
| * \note We do not recommend unregistering for the trace event unless it |
| * always returned #DR_EMIT_STORE_TRANSLATIONS, as doing so can prevent |
| * proper state translation on a later fault or other translation event. |
| * Instead of unregistering, turn the event callback into a nop. |
| */ |
| bool dr_unregister_trace_event(dr_emit_flags_t (*func)(void *drcontext, void *tag, |
| instrlist_t *trace, |
| bool translating)); |
| |
| /** |
| * DR will call the end trace event if it is registered prior to |
| * adding each basic block to a trace being generated. The return |
| * value of the event callback should be from the |
| * dr_custom_trace_action_t enum. |
| * |
| * \note DR treats CUSTOM_TRACE_CONTINUE as an advisement only. Certain |
| * fragments are not suitable to be included in a trace and if DR runs |
| * into one it will end the trace regardless of what the client returns |
| * through the event callback. |
| */ |
| typedef enum { |
| CUSTOM_TRACE_DR_DECIDES, |
| CUSTOM_TRACE_END_NOW, |
| CUSTOM_TRACE_CONTINUE |
| } dr_custom_trace_action_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the end-trace event. DR calls \p |
| * func before extending a trace with a new basic block. The \p func |
| * should return one of the #dr_custom_trace_action_t enum values. |
| */ |
| void dr_register_end_trace_event(dr_custom_trace_action_t (*func)(void *drcontext, |
| void *tag, |
| void *next_tag)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the end-trace event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool dr_unregister_end_trace_event(dr_custom_trace_action_t (*func)(void *drcontext, |
| void *tag, |
| void *next_tag)); |
| |
| /* For the new-bb-before-deletion-event problem (PR 495787, and |
| * described in the comment below): |
| * Note that we do not want a new "unreachable event" b/c clients need |
| * to keep bb info around in case the semi-flushed bb hits a fault. |
| * The main worry w/ the counter approach, in addition to ensuring |
| * it handles duplicates due to thread-private, is that can we |
| * guarantee that deletion events will be in order, or can a new |
| * fragment be deleted prior to older fragments? For most clients |
| * it won't matter I suppose. |
| */ |
| DR_API |
| /** |
| * Registers a callback function for the fragment deletion event. DR |
| * calls \p func whenever it removes a fragment from the code cache. |
| * Due to DR's high-performance non-precise flushing, a fragment |
| * can be made inaccessible but not actually freed for some time. |
| * A new fragment can thus be created before the deletion event |
| * for the old fragment is raised. We recommended using a counter |
| * to ignore subsequent deletion events when using per-fragment |
| * data structures and duplicate fragments are seen. |
| * |
| * \note drcontext may be NULL when thread-shared fragments are being |
| * deleted during process exit. For this reason, thread-private |
| * heap should not be used for data structures intended to be freed |
| * at thread-shared fragment deletion. |
| */ |
| void |
| dr_register_delete_event(void (*func)(void *drcontext, void *tag)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the fragment deletion event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_delete_event(void (*func)(void *drcontext, void *tag)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the machine state restoration event. |
| * DR calls \p func whenever it needs to translate a code cache machine |
| * context from the code cache to its corresponding original application |
| * context. DR needs to translate when instructions fault in the cache as |
| * well as when a suspended thread is examined or relocated for internal |
| * purposes. |
| * |
| * If a client is only adding instrumentation (meta-code: see |
| * #instr_is_meta()) that does not reference application memory, |
| * and is not reordering or removing application instructions, then it |
| * need not register for this event. If, however, a client is |
| * modifying application code or is adding code that can fault, the |
| * client must be capable of restoring the original context. |
| * |
| * When DR needs to translate a code cache context, DR recreates the |
| * faulting instruction's containing fragment, storing translation |
| * information along the way, by calling the basic block and/or trace event |
| * callbacks with the \p translating parameter set to true. DR uses the |
| * recreated code to identify the application instruction (\p mcontext.pc) |
| * corresponding to the faulting code cache instruction. If the client |
| * asked to store translation information by returning |
| * #DR_EMIT_STORE_TRANSLATIONS from the basic block or trace event |
| * callback, then this step of re-calling the event callback is skipped and |
| * the stored value is used as the application address (\p mcontext.pc). |
| * |
| * DR then calls the fault state restoration event to allow the client |
| * to restore the registers and application memory to their proper |
| * values as they would have appeared if the original application code |
| * had been executed up to the \p mcontext.pc instruction. Memory |
| * should only be restored if the \p restore_memory parameter is true; |
| * if it is false, DR may only be querying for the address (\p |
| * mcontext.pc) or register state and may not relocate this thread. |
| * |
| * DR will call this event for all translation attempts, even when the |
| * register state already contains application values, to allow |
| * clients to restore memory. |
| * |
| * The \p app_code_consistent parameter indicates whether the original |
| * application code containing the instruction being translated is |
| * guaranteed to still be in the same state it was when the code was |
| * placed in the code cache. This guarantee varies depending on the |
| * type of cache consistency being used by DR. |
| * |
| * The client can update \p mcontext.pc in this callback. The client |
| * should not change \p mcontext.flags: it should remain DR_MC_ALL. |
| * |
| * \note The passed-in \p drcontext may correspond to a different thread |
| * than the thread executing the callback. Do not assume that the |
| * executing thread is the target thread. |
| */ |
| void |
| dr_register_restore_state_event(void (*func)(void *drcontext, void *tag, |
| dr_mcontext_t *mcontext, bool restore_memory, |
| bool app_code_consistent)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the machine state restoration event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_restore_state_event(void (*func)(void *drcontext, void *tag, |
| dr_mcontext_t *mcontext, |
| bool restore_memory, |
| bool app_code_consistent)); |
| |
| /** |
| * Data structure passed within dr_exception_t, dr_siginfo_t, and |
| * dr_restore_state_info_t. |
| * Contains information about the code fragment inside the code cache |
| * at the exception/signal/translation interruption point. |
| */ |
| typedef struct _dr_fault_fragment_info_t { |
| /** |
| * The tag of the code fragment inside the code cache at the |
| * exception/signal/translation interruption point. NULL for |
| * interruption not in the code cache. |
| */ |
| void *tag; |
| /** |
| * The start address of the code fragment inside the code cache at |
| * the exception/signal/translation interruption point. NULL for interruption |
| * not in the code cache (in which case generally only unusual cases of clients |
| * changing memory require restoration). Clients are cautioned when examining |
| * code cache instructions to not rely on any details of code |
| * inserted other than their own. |
| */ |
| byte *cache_start_pc; |
| /** Indicates whether the interrupted code fragment is a trace */ |
| bool is_trace; |
| /** |
| * Indicates whether the original application code containing the |
| * code corresponding to the exception/signal/translation interruption point |
| * is guaranteed to still be in the same state it was when the |
| * code was placed in the code cache. This guarantee varies |
| * depending on the type of cache consistency being used by DR. |
| */ |
| bool app_code_consistent; |
| /** |
| * The recreated ilist for this fragment, which contains instrs added |
| * by the basic block event(s) with \p translating set to true and also |
| * DR's own mangling of some instrs. This includes client-added metadata |
| * in the form of notes and label instrs too. This may be helpful in |
| * restoring app state on a fault. |
| * When the recreated ilist is not available, this is set to NULL. This |
| * may happen when a client returns #DR_EMIT_STORE_TRANSLATIONS, or for |
| * DR internal reasons when the app code may not be consistent: for pending |
| * deletion or self-modifying fragments. It will also be NULL for non-code-cache |
| * cases where \p cache_start_pc is also NULL. |
| */ |
| instrlist_t *ilist; |
| } dr_fault_fragment_info_t; |
| |
| /** |
| * Data structure passed to a restore_state_ex event handler (see |
| * dr_register_restore_state_ex_event()). Contains the machine |
| * context at the translation point and other translation |
| * information. |
| */ |
| typedef struct _dr_restore_state_info_t { |
| /** |
| * The application machine state at the translation point. |
| * The client can update register values and the program counter |
| * by changing this context. The client should not change \p |
| * mcontext.flags: it should remain DR_MC_ALL. |
| */ |
| dr_mcontext_t *mcontext; |
| /** Whether raw_mcontext is valid. */ |
| bool raw_mcontext_valid; |
| /** |
| * The raw pre-translated machine state at the translation |
| * interruption point inside the code cache. Clients are |
| * cautioned when examining code cache instructions to not rely on |
| * any details of code inserted other than their own. |
| * Modifying this context will not affect the translation. |
| */ |
| dr_mcontext_t *raw_mcontext; |
| /** |
| * Information about the code fragment inside the code cache |
| * at the translation interruption point. |
| */ |
| dr_fault_fragment_info_t fragment_info; |
| } dr_restore_state_info_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the machine state restoration |
| * event with extended information. |
| * |
| * This event is identical to that for dr_register_restore_state_event() |
| * with the following exceptions: |
| * |
| * - Additional information is provided in the |
| * dr_restore_state_info_t structure, including the pre-translation |
| * context (containing the address inside the code cache of the |
| * translation point) and the starting address of the containing |
| * fragment in the code cache. Certain registers may not contain |
| * proper application values in \p info->raw_mcontext. Clients are |
| * cautioned against relying on any details of code cache layout or |
| * register usage beyond instrumentation inserted by the client |
| * itself when examining \p info->raw_mcontext. |
| * |
| * - The callback function returns a boolean indicating the success of |
| * the translation. When DR is translating not for a fault but for |
| * thread relocation, the \p restore_memory parameter will be false. |
| * Such translation can target a meta-instruction that can fault |
| * (i.e., it has a non-NULL translation field). For that scenario, a client |
| * can choose not to translate. Such instructions do not always |
| * require full translation for faults, and allowing translation |
| * failure removes the requirement that a client must translate at |
| * all such instructions. Note, however, that returning false can |
| * cause performance degradation as DR must then resume the thread |
| * and attempt to re-suspend it at a safer spot. Clients must |
| * return true for translation points in application code in order |
| * to avoid catastropic failure to suspend, and should thus identify |
| * whether translation points are inside their own instrumentation |
| * before returning false. Translation for relocation will never |
| * occur in meta instructions, so clients only need to look for |
| * meta-may-fault instructions. Clients should never return false |
| * when \p restore_memory is true. |
| * |
| * - If multiple callbacks are registered, the first one that returns |
| * false will short-circuit event delivery to later callbacks. |
| */ |
| void |
| dr_register_restore_state_ex_event(bool (*func)(void *drcontext, bool restore_memory, |
| dr_restore_state_info_t *info)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the machine state restoration |
| * event with extended ifnormation. \return true if unregistration is |
| * successful and false if it is not (e.g., \p func was not |
| * registered). |
| */ |
| bool |
| dr_unregister_restore_state_ex_event(bool (*func)(void *drcontext, bool restore_memory, |
| dr_restore_state_info_t *info)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the thread initialization event. |
| * DR calls \p func whenever the application creates a new thread. |
| */ |
| void |
| dr_register_thread_init_event(void (*func)(void *drcontext)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the thread initialization event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_thread_init_event(void (*func)(void *drcontext)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the thread exit event. DR calls |
| * \p func whenever an application thread exits. The passed-in |
| * drcontext should be used instead of calling |
| * dr_get_current_drcontext(), as the thread exit event may be invoked |
| * from other threads, and using dr_get_current_drcontext() can result |
| * in failure to clean up the right resources, and at process exit |
| * time it may return NULL. |
| * |
| * On Linux, SYS_execve may or may not result in a thread exit event. |
| * If the client registers its thread exit callback as a pre-SYS_execve |
| * callback as well, it must ensure that the callback acts as noop |
| * if called for the second time. |
| * |
| * On Linux, the thread exit event may be invoked twice for the same thread |
| * if that thread is alive during a process fork, but doesn't call the fork |
| * itself. The first time the event callback is executed from the fork child |
| * immediately after the fork, the second time it is executed during the |
| * regular thread exit. |
| * Clients may want to avoid touching resources shared between processes, |
| * like files, from the post-fork execution of the callback. The post-fork |
| * version of the callback can be recognized by dr_get_process_id() |
| * returning a different value than dr_get_process_id_from_drcontext(). |
| * |
| * See dr_set_process_exit_behavior() for options controlling performance |
| * and whether thread exit events are invoked at process exit time in |
| * release build. |
| */ |
| void |
| dr_register_thread_exit_event(void (*func)(void *drcontext)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the thread exit event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_thread_exit_event(void (*func)(void *drcontext)); |
| |
| /** |
| * Flags controlling thread behavior at process exit time in release build. |
| * See dr_set_process_exit_behavior() for further details. |
| */ |
| typedef enum { |
| /** |
| * Do not guarantee that the process exit event is executed |
| * single-threaded. This is equivalent to specifying the \p |
| * -multi_thread_exit runtime option. Setting this flag can improve |
| * process exit performance, but usually only when the |
| * #DR_EXIT_SKIP_THREAD_EXIT flag is also set, or when no thread exit |
| * events are registered. |
| */ |
| DR_EXIT_MULTI_THREAD = 0x01, |
| /** |
| * Do not invoke thread exit event callbacks at process exit time. |
| * Thread exit event callbacks will still be invoked at other times. |
| * This is equivalent to setting the \p -skip_thread_exit_at_exit |
| * runtime option. Setting this flag can improve process exit |
| * performance, but usually only when the #DR_EXIT_MULTI_THREAD flag is |
| * also set, or when no process exit event is registered. |
| */ |
| DR_EXIT_SKIP_THREAD_EXIT = 0x02, |
| } dr_exit_flags_t; |
| |
| DR_API |
| /** |
| * Specifies how process exit should be handled with respect to thread exit |
| * events and thread synchronization in release build. In debug build, and |
| * in release build by default, all threads are always synchronized at exit |
| * time, resulting in a single-threaded process exit event, and all thread |
| * exit event callbacks are always called. This routine can provide more |
| * performant exits in release build by avoiding the synchronization if the |
| * client is willing to skip thread exit events at process exit and is |
| * willing to execute its process exit event with multiple live threads. |
| */ |
| void |
| dr_set_process_exit_behavior(dr_exit_flags_t flags); |
| |
| DR_API |
| /** |
| * The #DR_DISALLOW_UNSAFE_STATIC declaration requests that DR perform sanity |
| * checks to ensure that client libraries will also operate safely when linked |
| * statically into an application. This overrides that request, facilitating |
| * having runtime options that are not supported in a static context. |
| */ |
| void |
| dr_allow_unsafe_static_behavior(void); |
| |
| #ifdef UNIX |
| DR_API |
| /** |
| * Registers a callback function for the fork event. DR calls \p func |
| * whenever the application forks a new process. |
| * \note Valid on Linux only. |
| */ |
| void |
| dr_register_fork_init_event(void (*func)(void *drcontext)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the fork event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_fork_init_event(void (*func)(void *drcontext)); |
| #endif |
| |
| DR_API |
| /** |
| * Registers a callback function for the module load event. DR calls |
| * \p func whenever the application loads a module (typically a |
| * library but this term includes the executable). The \p loaded |
| * parameter indicates whether the module is fully initialized by the |
| * loader or in the process of being loaded. This parameter is present |
| * only for backward compatibility: current versions of DR always pass true, |
| * and the client can assume that relocating, rebinding, and (on Linux) segment |
| * remapping have already occurred. |
| * |
| * \note The module_data_t \p info passed to the callback routine is |
| * valid only for the duration of the callback and should not be |
| * freed; a persistent copy can be made with dr_copy_module_data(). |
| * |
| * \note Registration cannot be done during the basic block event: it should be |
| * done at initialization time. |
| */ |
| void |
| dr_register_module_load_event(void (*func)(void *drcontext, const module_data_t *info, |
| bool loaded)); |
| |
| DR_API |
| /** |
| * Unregister a callback for the module load event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| * |
| * \note Unregistering for this event is not supported during the |
| * basic block event. |
| */ |
| bool |
| dr_unregister_module_load_event(void (*func)(void *drcontext, const module_data_t *info, |
| bool loaded)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the module unload event. DR |
| * calls \p func whenever the application unloads a module. |
| * \note The module_data_t \p *info passed to |
| * the callback routine is valid only for the duration of the callback |
| * and should not be freed; a persistent copy can be made with |
| * dr_copy_module_data(). |
| */ |
| void |
| dr_register_module_unload_event(void (*func)(void *drcontext, const module_data_t *info)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the module unload event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_module_unload_event(void (*func)(void *drcontext, |
| const module_data_t *info)); |
| |
| /** Identifies the type of kernel transfer for dr_register_kernel_xfer_event(). */ |
| typedef enum { |
| DR_XFER_SIGNAL_DELIVERY, /**< Signal delivery to application handler. */ |
| DR_XFER_SIGNAL_RETURN, /**< Signal return system call. */ |
| DR_XFER_APC_DISPATCHER, /**< Asynchronous procedure call dispatcher. */ |
| DR_XFER_EXCEPTION_DISPATCHER, /**< Exception dispatcher. */ |
| DR_XFER_RAISE_DISPATCHER, /**< Raised exception dispatcher. */ |
| DR_XFER_CALLBACK_DISPATCHER, /**< Callback dispatcher. */ |
| DR_XFER_CALLBACK_RETURN, /**< A return from a callback by syscall or interrupt. */ |
| DR_XFER_CONTINUE, /**< NtContinue system call. */ |
| DR_XFER_SET_CONTEXT_THREAD, /**< NtSetContextThread system call. */ |
| DR_XFER_CLIENT_REDIRECT, /**< dr_redirect_execution() or #DR_SIGNAL_REDIRECT. */ |
| /** |
| * A Linux restartable sequence was aborted. The interrupted PC for a signal in |
| * the execution instrumentation points to the precise interrupted |
| * instruction; but for an abort in the native exeuction, the PC always points |
| * to the abort handler, rather than the precise instruction that was aborted. |
| * This aligns with kernel behavior: the interrupted PC is not saved anywhere. |
| */ |
| DR_XFER_RSEQ_ABORT, |
| } dr_kernel_xfer_type_t; |
| |
| /** Data structure passed for dr_register_kernel_xfer_event(). */ |
| typedef struct _dr_kernel_xfer_info_t { |
| /** The type of event. */ |
| dr_kernel_xfer_type_t type; |
| /** |
| * The source machine context which is about to be changed. This may be NULL |
| * if it is unknown, which is the case for #DR_XFER_CALLBACK_DISPATCHER. |
| * For #DR_XFER_RSEQ_ABORT, due to the constraints of handling restartable |
| * sequences, the abort PC will point prior to the committing store, while |
| * that store already executed during instrumentation. We recommend that |
| * clients treat the store as never-executed in that situation, if possible, |
| * to produce a more-representative sequence. |
| */ |
| const dr_mcontext_t *source_mcontext; |
| /** |
| * The target program counter of the transfer. To obtain the full target state, |
| * call dr_get_mcontext(). (For efficiency purposes, only frequently needed |
| * state is included by default.) |
| */ |
| app_pc target_pc; |
| /** |
| * The target stack pointer of the transfer. To obtain the full target state, |
| * call dr_get_mcontext(). (For efficiency purposes, only frequently needed |
| * state is included by default.) |
| */ |
| reg_t target_xsp; |
| /** For #DR_XFER_SIGNAL_DELIVERY and #DR_XFER_SIGNAL_RETURN, the signal number. */ |
| int sig; |
| } dr_kernel_xfer_info_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the kernel transfer event. DR |
| * calls \p func whenever the kernel is about to directly transfer control |
| * without an explicit user-mode control transfer instruction. |
| * This includes the following scenarios, which are distinguished by \p type: |
| * - On UNIX, a signal is about to be delivered to an application handler. |
| * This event differs from a dr_register_signal_event() callback in that the |
| * latter is called regardless of whether the application has a handler, |
| * and it does not provide the target context of any handler. |
| * - On UNIX, a signal return system call is about to be invoked. |
| * - On Windows, the asynchronous procedure call dispatcher is about to be invoked. |
| * - On Windows, the callback dispatcher is about to be invoked. |
| * - On Windows, the exception dispatcher is about to be invoked. |
| * - On Windows, the NtContinue system call is about to be invoked. |
| * - On Windows, the NtSetContextThread system call is about to be invoked. |
| * - On Windows, the NtCallbackReturn system call is about to be invoked. |
| * - On Windows, interrupt 0x2b is about to be invoked. |
| * - The client requests redirection using dr_redirect_execution() or |
| * #DR_SIGNAL_REDIRECT. |
| * |
| * The prior context, if known, is provided in \p info->source_mcontext; if |
| * unknown, \p info->source_mcontext is NULL. Multimedia state is typically |
| * not provided in \p info->source_mcontext, which is reflected in its \p flags. |
| * |
| * The target program counter and stack are provided in \p info->target_pc and \p |
| * info->target_xsp. Further target state can be examined by calling |
| * dr_get_mcontext() and modified by calling dr_set_mcontext(). Changes to the |
| * target state, including the pc, are supported for all cases except |
| * NtCallbackReturn and interrupt 0x2b. However, dr_get_mcontext() and |
| * dr_set_mcontext() are limited for the Windows system calls NtContinue and |
| * NtSetContextThread to the ContextFlags set by the application: dr_get_mcontext() |
| * will adjust the dr_mcontext_t.flags to reflect what's available, and |
| * dr_set_mcontext() will only set what's also set in ContextFlags. Given the |
| * disparity in how Ebp/Rbp is handled (in #DR_MC_INTEGER but in CONTEXT_CONTROL), |
| * clients that care about that register are better off using system call events |
| * instead of kernel transfer events to take actions on these two system calls. |
| * |
| * This is a convenience event: all of the above events can be detected using |
| * combinations of other events. This event is meant to be used to identify all |
| * changes in the program counter that do not arise from explicit control flow |
| * instructions. |
| */ |
| void |
| dr_register_kernel_xfer_event(void (*func)(void *drcontext, |
| const dr_kernel_xfer_info_t *info)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the kernel transfer event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_kernel_xfer_event(void (*func)(void *drcontext, |
| const dr_kernel_xfer_info_t *info)); |
| |
| #ifdef WINDOWS |
| |
| /** |
| * Data structure passed with an exception event. Contains the |
| * machine context and the Win32 exception record. |
| */ |
| typedef struct _dr_exception_t { |
| /** |
| * Machine context at exception point. The client should not |
| * change \p mcontext->flags: it should remain DR_MC_ALL. |
| */ |
| dr_mcontext_t *mcontext; |
| EXCEPTION_RECORD *record; /**< Win32 exception record. */ |
| /** |
| * The raw pre-translated machine state at the exception interruption |
| * point inside the code cache. Clients are cautioned when examining |
| * code cache instructions to not rely on any details of code inserted |
| * other than their own. |
| * The client should not change \p raw_mcontext.flags: it should |
| * remain DR_MC_ALL. |
| */ |
| dr_mcontext_t *raw_mcontext; |
| /** |
| * Information about the code fragment inside the code cache at |
| * the exception interruption point. |
| */ |
| dr_fault_fragment_info_t fault_fragment_info; |
| } dr_exception_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the exception event. DR calls \p func |
| * whenever the application throws an exception. If \p func returns true, |
| * the exception is delivered to the application's handler along with any |
| * changes made to \p excpt->mcontext. If \p func returns false, the |
| * faulting instruction in the code cache is re-executed using \p |
| * excpt->raw_mcontext, including any changes made to that structure. |
| * Clients are expected to use \p excpt->raw_mcontext when using faults as |
| * a mechanism to push rare cases out of an instrumentation fastpath that |
| * need to examine instrumentation instructions rather than the translated |
| * application state and should normally not examine it for application |
| * instruction faults. Certain registers may not contain proper |
| * application values in \p excpt->raw_mcontext for exceptions in |
| * application instructions. Clients are cautioned against relying on any |
| * details of code cache layout or register usage beyond instrumentation |
| * inserted by the client itself when examining \p excpt->raw_mcontext. |
| * |
| * If multiple callbacks are registered, the first one that returns |
| * false will short-circuit event delivery to later callbacks. |
| * |
| * DR raises this event for exceptions outside the code cache that |
| * could come from code generated by a client. For such exceptions, |
| * mcontext is not translated and is identical to raw_mcontext. |
| * |
| * To skip the passing of the exception to the application's exception |
| * handlers and to send control elsewhere instead, a client can call |
| * dr_redirect_execution() from \p func. |
| * |
| * \note \p excpt->fault_fragment_info data is provided with |
| * \p excpt->raw_mcontext. It is valid only if |
| * \p excpt->fault_fragment_info.cache_start_pc is not \p NULL. |
| * It provides clients information about the code fragment being |
| * executed at the exception interruption point. Clients are cautioned |
| * against relying on any details of code cache layout or register |
| * usage beyond instrumentation inserted by the client itself. |
| * \note Only valid on Windows. |
| * \note The function is not called for RaiseException. |
| */ |
| void |
| dr_register_exception_event(bool (*func)(void *drcontext, dr_exception_t *excpt)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the exception event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_exception_event(bool (*func)(void *drcontext, dr_exception_t *excpt)); |
| #endif /* WINDOWS */ |
| |
| DR_API |
| /** |
| * Registers a callback function for the syscall filter event. DR |
| * calls \p func to decide whether to invoke the syscall events for |
| * each system call site encountered with a statically-determinable |
| * system call number. If \p func returns true, the pre-syscall |
| * (dr_register_pre_syscall_event()) and post-syscall |
| * (dr_register_post_syscall_event()) events will be invoked. |
| * Otherwise, the events may or may not occur, depending on whether DR |
| * itself needs to intercept them and whether the system call number |
| * is statically determinable. System call number determination can |
| * depend on whether the -opt_speed option is enabled. If a system |
| * call number is not determinable, the filter event will not be |
| * called, but the pre and post events will be called. |
| * |
| * Intercepting every system call can be detrimental to performance |
| * for certain types of applications. Filtering provides for greater |
| * performance by letting uninteresting system calls execute without |
| * interception overhead. |
| */ |
| void |
| dr_register_filter_syscall_event(bool (*func)(void *drcontext, int sysnum)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the syscall filter event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_filter_syscall_event(bool (*func)(void *drcontext, int sysnum)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the pre-syscall event. DR calls |
| * \p func whenever the application is about to invoke a system call, |
| * if any client asked for that system call number to be intercepted |
| * via the filter event (dr_register_filter_syscall_event()). |
| * Any client registering a pre- or post-syscall event should also |
| * register a filter event. |
| * |
| * The application parameters to the system call can be viewed with |
| * dr_syscall_get_param() and set with dr_syscall_set_param(). The |
| * system call number can also be changed with |
| * dr_syscall_set_sysnum(). |
| * |
| * The application's machine state can be accessed and set with |
| * dr_get_mcontext() and dr_set_mcontext(). Changing registers in |
| * this way overlaps with system call parameter changes on some |
| * platforms. On Linux, for SYS_clone, client changes to the ebp/rbp |
| * register will be ignored by the clone child. |
| * |
| * On MacOS, whether 32-bit or 64-bit, the system call number passed |
| * (\p sysnum) has been normalized to a positive number with the top 8 |
| * bits set to 0x1 for a Mach system call, 0x3 for Machdep, and 0x0 |
| * for BSD (allowing the direct use of SYS_ constants). Access the |
| * raw eax register to view the unmodified number. |
| * |
| * If \p func returns true, the application's system call is invoked |
| * normally; if \p func returns false, the system call is skipped. If |
| * it is skipped, the return value can be set with |
| * dr_syscall_set_result() or dr_syscall_set_result_ex(). If the |
| * system call is skipped, there will not be a post-syscall event. |
| * If multiple callbacks are registered, the first one that returns |
| * false will short-circuit event delivery to later callbacks. |
| */ |
| void |
| dr_register_pre_syscall_event(bool (*func)(void *drcontext, int sysnum)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the pre-syscall event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_pre_syscall_event(bool (*func)(void *drcontext, int sysnum)); |
| |
| DR_API |
| /** |
| * Registers a callback function for the post-syscall event. DR calls |
| * \p func whenever the application just finished invoking a system |
| * call, if any client asked for that system call number to be |
| * intercepted via the filter event |
| * (dr_register_filter_syscall_event()) or if DR itself needs to |
| * intercept the system call. |
| * Any client registering a pre- or post-syscall event should also |
| * register a filter event. |
| * |
| * The result of the system call can be modified with |
| * dr_syscall_set_result() or dr_syscall_set_result_ex(). |
| * |
| * System calls that change control flow or terminate the current |
| * thread or process typically do not have a post-syscall event. |
| * These include SYS_exit, SYS_exit_group, SYS_execve, SYS_sigreturn, |
| * and SYS_rt_sigreturn on Linux, and NtTerminateThread, |
| * NtTerminateProcess (depending on the parameters), NtCallbackReturn, |
| * and NtContinue on Windows. |
| * |
| * The application's machine state can be accessed and set with |
| * dr_get_mcontext() and dr_set_mcontext(). |
| * |
| * On MacOS, whether 32-bit or 64-bit, the system call number passed |
| * (\p sysnum) has been normalized to a positive number with the top 8 |
| * bits set to 0x1 for a Mach system call, 0x3 for Machdep, and 0x0 |
| * for BSD (allowing the direct use of SYS_ constants). Access the |
| * raw eax register to view the unmodified number. |
| * |
| * Additional system calls may be invoked by calling |
| * dr_syscall_invoke_another() prior to returning from the |
| * post-syscall event callback. The system call to be invoked should |
| * be specified with dr_syscall_set_sysnum(), and its parameters can |
| * be set with dr_syscall_set_param(). |
| */ |
| void |
| dr_register_post_syscall_event(void (*func)(void *drcontext, int sysnum)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the post-syscall event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_post_syscall_event(void (*func)(void *drcontext, int sysnum)); |
| |
| #ifdef UNIX |
| |
| /* XXX: for PR 304708 I originally included siginfo_t in |
| * dr_siginfo_t. But can we really trust siginfo_t to be identical on |
| * all supported platforms? Esp. once we start supporting VMKUW, |
| * MacOS, etc. I'm removing it for now. None of my samples need it, |
| * and in my experience its fields are unreliable in any case. |
| * PR 371370 covers re-adding it if users request it. |
| * If we re-add it, we should use our kernel_siginfo_t version. |
| */ |
| /** |
| * Data structure passed with a signal event. Contains the machine |
| * context at the signal interruption point and other signal |
| * information. |
| */ |
| typedef struct _dr_siginfo_t { |
| /** The signal number. */ |
| int sig; |
| /** The context of the thread receiving the signal. */ |
| void *drcontext; |
| /** |
| * The application machine state at the signal interruption point. |
| * The client should not change \p mcontext.flags: it should |
| * remain DR_MC_ALL. |
| */ |
| dr_mcontext_t *mcontext; |
| /** |
| * The raw pre-translated machine state at the signal interruption |
| * point inside the code cache. NULL for delayable signals. Clients |
| * are cautioned when examining code cache instructions to not rely on |
| * any details of code inserted other than their own. |
| * The client should not change \p mcontext.flags: it should |
| * remain DR_MC_ALL. |
| */ |
| dr_mcontext_t *raw_mcontext; |
| /** Whether raw_mcontext is valid. */ |
| bool raw_mcontext_valid; |
| /** |
| * For SIGBUS and SIGSEGV, the address whose access caused the signal |
| * to be raised (as calculated by DR). |
| */ |
| byte *access_address; |
| /** |
| * Indicates this signal is blocked. DR_SIGNAL_BYPASS is not allowed, |
| * and a second event will be sent if the signal is later delivered to |
| * the application. Events are only sent for blocked non-delayable signals, |
| * not for delayable signals. |
| */ |
| bool blocked; |
| /** |
| * Information about the code fragment inside the code cache |
| * at the signal interruption point. |
| */ |
| dr_fault_fragment_info_t fault_fragment_info; |
| } dr_siginfo_t; |
| |
| /** |
| * Return value of client signal event callback, determining how DR will |
| * proceed with the signal. |
| */ |
| typedef enum { |
| /** Deliver signal to the application as normal. */ |
| DR_SIGNAL_DELIVER, |
| /** Suppress signal as though it never happened. */ |
| DR_SIGNAL_SUPPRESS, |
| /** |
| * Deliver signal according to the default SIG_DFL action, as would |
| * happen if the application had no handler. |
| */ |
| DR_SIGNAL_BYPASS, |
| /** |
| * Do not deliver the signal. Instead, redirect control to the |
| * application state specified in dr_siginfo_t.mcontext. |
| * Clients may modify dr_siginfo_t.mcontext.pc to redirect control to |
| * a desired pc, but beware that it is important to set the app state |
| * (like the register values) as expected by the transfer point. |
| */ |
| DR_SIGNAL_REDIRECT, |
| } dr_signal_action_t; |
| |
| DR_API |
| /** |
| * Requests that DR call the provided callback function \p func whenever a |
| * signal is received by any application thread. The return value of \p |
| * func determines whether DR delivers the signal to the application. |
| * To redirect execution return DR_SIGNAL_REDIRECT (do not call |
| * dr_redirect_execution() from a signal callback). The callback function |
| * will be called even if the application has no handler or has registered |
| * a SIG_IGN or SIG_DFL handler. If multiple callbacks are registered, |
| * the first one that returns other than DR_SIGNAL_DELIVER will short-circuit |
| * event delivery to later callbacks. |
| * |
| * Modifications to the fields of \p siginfo->mcontext will be propagated |
| * to the application if it has a handler for the signal, if |
| * DR_SIGNAL_DELIVER is returned. |
| * |
| * The \p siginfo->raw_mcontext data is only provided for non-delayable |
| * signals (e.g., SIGSEGV) that must be delivered immediately. Whether it |
| * is supplied is specified in \p siginfo->raw_mcontext_valid. It is |
| * intended for clients using faults as a mechanism to push rare cases out |
| * of an instrumentation fastpath that need to examine instrumentation |
| * instructions rather than the translated application state. Certain |
| * registers may not contain proper application values in \p |
| * excpt->raw_mcontext for exceptions in application instructions. Clients |
| * are cautioned against relying on any details of code cache layout or |
| * register usage beyond instrumentation inserted by the client itself. If |
| * DR_SIGNAL_SUPPRESS is returned, \p siginfo->mcontext is ignored and \p |
| * siginfo->raw_mcontext is used as the resumption context. The client's |
| * changes to \p siginfo->raw_mcontext will take effect. |
| * |
| * For a delayable signal, DR raises a signal event only when about to |
| * deliver the signal to the application. Thus, if the application has |
| * blocked a delayable signal, the corresponding signal event will not |
| * occur until the application unblocks the signal, even if such a signal |
| * is delivered by the kernel. For non-delayable signals, DR will raise a |
| * signal event on initial receipt of the signal, with the \p |
| * siginfo->blocked field set. Such a blocked signal will have a second |
| * event raised when it is delivered to the application (if it is not |
| * suppressed by the client, and if there is not already a pending blocked |
| * signal, for non-real-time signals). |
| * |
| * DR raises this event for faults outside the code cache that |
| * could come from code generated by a client. For such cases, |
| * mcontext is not translated and is identical to raw_mcontext. |
| * |
| * DR will not raise a signal event for a SIGSEGV or SIGBUS |
| * raised by a client code fault rather than the application. Use |
| * dr_safe_read(), dr_safe_write(), or DR_TRY_EXCEPT() to prevent such |
| * faults. |
| * |
| * \note \p siginfo->fault_fragment_info data is provided |
| * with \p siginfo->raw_mcontext. It is valid only if |
| * \p siginfo->fault_fragment_info.cache_start_pc is not |
| * \p NULL. It provides clients information about the code fragment |
| * being executed at the signal interruption point. Clients are |
| * cautioned against relying on any details of code cache layout or |
| * register usage beyond instrumentation inserted by the client |
| * itself. |
| * |
| * \note Only valid on Linux. |
| * |
| * \note DR always requests SA_SIGINFO for all signals. |
| * |
| * \note This version of DR does not intercept the signals SIGCONT, |
| * SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU. Future versions should add |
| * support for these signals. |
| * |
| * \note If the client uses signals for its own communication it should set |
| * a flag to distinguish its own uses of signals from the application's |
| * use. Races where the two are re-ordered should not be problematic. |
| */ |
| void dr_register_signal_event(dr_signal_action_t (*func)(void *drcontext, |
| dr_siginfo_t *siginfo)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the signal event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool dr_unregister_signal_event(dr_signal_action_t (*func)(void *drcontext, |
| dr_siginfo_t *siginfo)); |
| #endif /* UNIX */ |
| |
| DR_API |
| /** |
| * Registers a callback function for the low on memory event. DR calls \p func |
| * whenever virtual memory is tight and enables the client to help free space. |
| */ |
| void |
| dr_register_low_on_memory_event(void (*func)()); |
| |
| DR_API |
| /** |
| * Unregister a callback function for low on memory events. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., the function was not registered). |
| */ |
| bool |
| dr_unregister_low_on_memory_event(void (*func)()); |
| |
| DR_API |
| /** |
| * Registers a callback function that is invoked whenever a clean call is inserted |
| * in instrumentation, such as by dr_insert_clean_call(), dr_insert_clean_call_ex(), |
| * or dr_insert_clean_call_ex_varg(). |
| * 'where' is a label with note value #DR_NOTE_CLEAN_CALL_END; the clean call |
| * sequence will be inserted prior to the label after all clean call callbacks |
| * are finished (so the clean call sequence is not yet visible at the time this |
| * callback is invoked). |
| */ |
| void |
| dr_register_clean_call_insertion_event(void (*func)(void *drcontext, instrlist_t *ilist, |
| instr_t *where, |
| dr_cleancall_save_t call_flags)); |
| |
| DR_API |
| /** |
| * Unregisters a callback function that was registered with |
| * dr_register_call_insertion_event(). |
| */ |
| bool |
| dr_unregister_clean_call_insertion_event(void (*func)(void *drcontext, instrlist_t *ilist, |
| instr_t *where, |
| dr_cleancall_save_t call_flags)); |
| |
| /**************************************************************************** |
| * SECURITY SUPPORT |
| */ |
| |
| #ifdef PROGRAM_SHEPHERDING |
| |
| /** Types of security violations that can be received at a security violation event |
| * callback. |
| * - DR_RCO_* : |
| * A violation of the Restricted Code Origins policies. The target address is not |
| * in an allowed execution area. |
| * - DR_RCO_STACK_VIOLATION - The target address is on the current thread's stack. |
| * - DR_RCO_HEAP_VIOLATION - The target address is not on the current thread's stack. |
| * - DR_RCT_* : |
| * A violation of the Restricted Control Transfer policies. The transition from the |
| * source address to the target address is not allowed. |
| * - DR_RCT_RETURN_VIOLATION - The transition from source_pc to target_pc is via a |
| * return instruction. The target address does not follow an executed call |
| * instruction and is not exempted. |
| * - DR_RCT_INDIRECT_CALL_VIOLATION - The transition from source_pc to target_pc is |
| * via an indirect call instruction. |
| * - DR_RCT_INDIRECT_JUMP_VIOLATION - The transition from source_pc to target_pc is |
| * via an indirect jmp instruction. |
| * - DR_UNKNOWN_VIOLATION : |
| * An unknown violation type, the client shouldn't expect to see this. |
| */ |
| typedef enum { |
| DR_RCO_STACK_VIOLATION, |
| DR_RCO_HEAP_VIOLATION, |
| DR_RCT_RETURN_VIOLATION, |
| DR_RCT_INDIRECT_CALL_VIOLATION, |
| DR_RCT_INDIRECT_JUMP_VIOLATION, |
| DR_UNKNOWN_VIOLATION, |
| } dr_security_violation_type_t; |
| |
| /** Types of remediations available at a security violation event callback. |
| * - DR_VIOLATION_ACTION_CONTINUE : |
| * Continue application execution as if no violation occurred. Use this if the |
| * violation is determined to be a false positive. |
| * - DR_VIOLATION_ACTION_CONTINUE_CHANGED_CONTEXT : |
| * Continue application execution after applying any changes made to the mcontext. |
| * Use this to fix up the application's state and continue execution. |
| * - DR_VIOLATION_ACTION_KILL_PROCESS : |
| * Immediately kills the process. This is the safest course of action to take |
| * when faced with possibly corrupt application state, but availability concerns |
| * may dictate using one of the other choices, since they can be less disruptive. |
| * - DR_VIOLATION_ACTION_KILL_THREAD : |
| * Immediately kills the thread that caused the violation (the current thread). |
| * If the current thread is part of a pool of worker threads kept by the application |
| * then it's likely the application will recover gracefully. If the thread is |
| * responsible for a particular function within the application (such as a |
| * particular service within an svchost process) then the application may continue |
| * with only that functionality lost. Note that no cleanup of the thread's state |
| * is preformed (application locks it owns are not released and, for Windows NT and |
| * 2000 its stack is not freed). However, the client will still receive the thread |
| * exit event for this thread. |
| * - DR_VIOLATION_ACTION_THROW_EXCEPTION : |
| * Causes the application to receive an unreadable memory execution exception in |
| * the thread that caused the violation (the current thread). The exception will |
| * appear to originate from an application attempt to execute from the target |
| * address. If the application has good exception handling it may recover |
| * gracefully. |
| */ |
| typedef enum { |
| DR_VIOLATION_ACTION_CONTINUE, |
| DR_VIOLATION_ACTION_CONTINUE_CHANGED_CONTEXT, |
| DR_VIOLATION_ACTION_KILL_PROCESS, |
| DR_VIOLATION_ACTION_KILL_THREAD, |
| DR_VIOLATION_ACTION_THROW_EXCEPTION, |
| } dr_security_violation_action_t; |
| |
| DR_API |
| /** |
| * Registers a callback function for the security violation event. DR |
| * calls \p func whenever it intercepts a security violation. Clients |
| * can override the default remediation by changing \p action. If |
| * multiple callbacks are registered, the callback registered last has |
| * final control over the action. \note source_pc can be NULL if DR |
| * fails to recreate the source pc. |
| */ |
| void |
| dr_register_security_event(void (*func)(void *drcontext, void *source_tag, |
| app_pc source_pc, app_pc target_pc, |
| dr_security_violation_type_t violation, |
| dr_mcontext_t *mcontext, |
| dr_security_violation_action_t *action)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the security violation event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_security_event(void (*func)(void *drcontext, void *source_tag, |
| app_pc source_pc, app_pc target_pc, |
| dr_security_violation_type_t violation, |
| dr_mcontext_t *mcontext, |
| dr_security_violation_action_t *action)); |
| #endif /* PROGRAM_SHEPHERDING */ |
| |
| DR_API |
| /** |
| * Registers a callback function for nudge events. External entities |
| * can nudge a process through the dr_nudge_process() or |
| * dr_nudge_pid() drconfig API routines on Windows or using the \p |
| * drnudgeunix tool on Linux. A client in this process can use |
| * dr_nudge_client() to raise a nudge, while a client in another |
| * process can use dr_nudge_client_ex(). |
| * |
| * DR calls \p func whenever the current process receives a nudge. |
| * On Windows, the nudge event is delivered in a new non-application |
| * thread. Callers must specify the target client by passing the |
| * client ID that was provided in dr_client_main(). |
| */ |
| void |
| dr_register_nudge_event(void (*func)(void *drcontext, uint64 argument), client_id_t id); |
| |
| DR_API |
| /** |
| * Unregister a callback function for the nudge event. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., \p func was not registered). |
| */ |
| bool |
| dr_unregister_nudge_event(void (*func)(void *drcontext, uint64 argument), client_id_t id); |
| |
| DR_API |
| /** |
| * Triggers an asynchronous nudge event in the current process. The callback |
| * function registered with dr_register_nudge_event() will be called with the |
| * supplied \p argument (in a new non-application thread on Windows). |
| * |
| * \note On Linux, the nudge will not be delivered until this thread exits |
| * the code cache. Thus, if this routine is called from a clean call, |
| * dr_redirect_execution() should be used to ensure cache exit. |
| */ |
| bool |
| dr_nudge_client(client_id_t id, uint64 argument); |
| |
| DR_API |
| /** |
| * Triggers an asynchronous nudge event in a target process. The callback |
| * function registered with dr_register_nudge_event() for the |
| * specified client in the specified process will be called with the |
| * supplied \p argument (in a new non-application thread on Windows). |
| * |
| * \note On Linux, if \p pid is the current process, the nudge will |
| * not be delivered until this thread exits the code cache. Thus, if |
| * this routine is called from a clean call and \p pid is the current |
| * process, dr_redirect_execution() should be used to ensure cache exit. |
| * |
| * \param[in] process_id The system id of the process to nudge |
| * (see dr_get_process_id()) |
| * |
| * \param[in] client_id The unique client ID provided at client |
| * registration. |
| * |
| * \param[in] argument An argument passed to the client's nudge |
| * handler. |
| * |
| * \param[in] timeout_ms Windows only. The number of milliseconds to wait for |
| * each nudge to complete before continuing. If INFINITE |
| * is supplied then the wait is unbounded. If 0 |
| * is supplied the no wait is performed. If a |
| * non-0 wait times out DR_NUDGE_TIMEOUT will be returned. |
| * |
| * \return A dr_config_status_t code indicating the result of the nudge. |
| */ |
| dr_config_status_t |
| dr_nudge_client_ex(process_id_t process_id, client_id_t client_id, uint64 argument, |
| uint timeout_ms); |
| |
| #ifdef WINDOWS |
| DR_API |
| /** |
| * On Windows, nudges are implemented via remotely injected threads. |
| * This routine returns whether or not the thread indicated by |
| * \p drcontext is such a nudge thread. |
| * \note Windows only. |
| */ |
| bool |
| dr_is_nudge_thread(void *drcontext); |
| #endif |
| |
| /**************************************************************************** |
| * PERSISTENT CACHE SUPPORT |
| */ |
| |
| DR_API |
| /** |
| * Takes in the \p perscxt opaque parameter passed to various persistence |
| * events and returns the beginning address of the code region being |
| * persisted. |
| */ |
| app_pc |
| dr_persist_start(void *perscxt); |
| |
| DR_API |
| /** |
| * Takes in the \p perscxt opaque parameter passed to various persistence |
| * events and returns the size of the code region being persisted. |
| */ |
| size_t |
| dr_persist_size(void *perscxt); |
| |
| DR_API |
| /** |
| * Takes in the \p perscxt opaque parameter passed to various |
| * persistence events and returns whether the fragment identified by |
| * \p tag is being persisted. This routine can be called outside of a |
| * persistence event, in which case the \p perscxt parameter should be |
| * NULL. |
| */ |
| bool |
| dr_fragment_persistable(void *drcontext, void *perscxt, void *tag); |
| |
| DR_API |
| /** |
| * Registers callback functions for storing read-only data in each persisted |
| * cache file. When generating a new persisted cache file, DR first calls \p |
| * func_size to obtain the size required for read-only data in each persisted |
| * cache file. DR subsequently calls \p func_persist to write the actual data. |
| * DR ensures that no other thread will execute in between the calls |
| * to \p func_size and \p func_persist. |
| * |
| * Upon loading a previously-written persisted cache file, DR calls \p |
| * func_resurrect to validate and read back in data from the persisted file. |
| * |
| * For each callback, the \p perscxt parameter can be passed to the routines |
| * dr_persist_start(), dr_persist_size(), and dr_fragment_persistable() to |
| * identify the region of code being persisted. |
| * |
| * @param[in] func_size The function to call to determine the size needed for |
| * persisted data. The \p file_offs parameter indicates the offset from the start |
| * of the persisted file where this data will reside (which is needed to |
| * calculate patch displacements). The callback can store a void* value into |
| * the address specified by \p user_data. This value will be passed to \p |
| * func_persist and if a patch callback is registered (see |
| * dr_register_persist_patch()) to \p func_patch. The same value will be |
| * shared with persisted code callbacks (see dr_register_persist_rx()) and |
| * writable data callbacks (see dr_register_persist_rw()). |
| * @param[in] func_persist The function to call to write the actual data. |
| * Data to be persisted should be written to the file \p fd via |
| * dr_write_file(). The data will be read-only when the persisted file is |
| * loaded back in for use. The return value of the function indicates success |
| * of the write. If the function returns false, the persisted cache file |
| * being generated will be abandoned under the assumption of a non-recoverable |
| * error. |
| * @param[in] func_resurrect The function to call to validate previously written data. |
| * The \p map variable points to the mapped-in data that was written at |
| * persist time. The return value of the function indicates success of the |
| * resurrection. If the function returns false, the persisted cache file |
| * being loaded will be abandoned under the assumption of a non-recoverable |
| * error. Any validation that the persisted file is suitable for use should |
| * be performed by the function prior to any restoration work needed for the |
| * data. The \p map address should be updated to point to the end of |
| * the persisted data (i.e., on return it should equal its start value plus |
| * the size that was passed to dr_register_persist_ro_size()). |
| * DR will perform self-consistency checks, including whether the |
| * whole pcache is present and that a checksum of at least part of |
| * the file matches, prior to calling this callback. Thus, the |
| * client can assume that it is not truncated. |
| * \note \p func_resurrect may be called during persisted file generation if |
| * a persisted file already exists, in order to merge with that file. |
| * \return whether successful. |
| */ |
| bool |
| dr_register_persist_ro( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * Unregister callback functions for storing read-only data in a persisted cache file. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., one of the functions was not registered). |
| */ |
| bool |
| dr_unregister_persist_ro( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * Registers callback functions for storing executable code (outside of normal |
| * code blocks) in each persisted cache file. When generating a new persisted |
| * cache file, DR first calls \p func_size to obtain the size required for |
| * executable code in each persisted cache file. DR subsequently calls \p |
| * func_persist to write the actual code. |
| * DR ensures that no other thread will execute in between the calls |
| * to \p func_size and \p func_persist. |
| * |
| * Upon loading a previously-written persisted cache file, DR calls \p |
| * func_resurrect to validate and read back in code from the persisted |
| * file. |
| * |
| * For each callback, the \p perscxt parameter can be passed to the routines |
| * dr_persist_start(), dr_persist_size(), and dr_fragment_persistable() to |
| * identify the region of code being persisted. |
| * |
| * @param[in] func_size The function to call to determine the size needed |
| * for persisted code. The \p file_offs parameter indicates the offset from the start |
| * of the persisted file where this code will reside (which is needed to |
| * calculate patch displacements). The callback can store a void* value into |
| * the address specified by \p user_data. This value will be passed to \p |
| * func_persist and if a patch callback is registered (see |
| * dr_register_persist_patch()) to \p func_patch. The same value will be |
| * shared with read-only data callbacks (see dr_register_persist_ro()) and |
| * writable data callbacks (see dr_register_persist_rw()). |
| * @param[in] func_persist The function to call to write the actual code. |
| * Code to be persisted should be written to the file \p fd via |
| * dr_write_file(). The code will be read-only when the persisted file is |
| * loaded back in for use. The return value of the function indicates success |
| * of the write. If the function returns false, the persisted cache file |
| * being generated will be abandoned under the assumption of a non-recoverable |
| * error. |
| * @param[in] func_resurrect The function to call to validate previously written code. |
| * The \p map variable points to the mapped-in code that was written at |
| * persist time. The return value of the function indicates success of the |
| * resurrection. If the function returns false, the persisted cache file |
| * being loaded will be abandoned under the assumption of a non-recoverable |
| * error. Any validation that the persisted file is suitable for use should |
| * be performed by the function prior to any restoration work needed for the |
| * code. The \p map address should be updated to point to the end of |
| * the persisted data (i.e., on return it should equal its start value plus |
| * the size that was passed to dr_register_persist_rx_size()). |
| * DR will perform self-consistency checks, including whether the |
| * whole pcache is present and that a checksum of at least part of |
| * the file matches, prior to calling this callback. Thus, the |
| * client can assume that it is not truncated. |
| * \note \p func_resurrect may be called during persisted file generation if |
| * a persisted file already exists, in order to merge with that file. |
| * \return whether successful. |
| */ |
| bool |
| dr_register_persist_rx( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * Unregister callback functions for storing executable code in a persisted cache file. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., one of the functions was not registered). |
| */ |
| bool |
| dr_unregister_persist_rx( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * Registers callback functions for storing writable data in each persisted |
| * cache file. When generating a new persisted cache file, DR first calls \p |
| * func_size to obtain the size required for writable data in each persisted |
| * cache file. DR subsequently calls \p func_persist to write the actual data. |
| * DR ensures that no other thread will execute in between the calls |
| * to \p func_size and \p func_persist. |
| * |
| * Upon loading a previously-written persisted cache file, DR calls \p |
| * func_resurrect to validate and read back in data from the persisted file. |
| * |
| * For each callback, the \p perscxt parameter can be passed to the routines |
| * dr_persist_start(), dr_persist_size(), and dr_fragment_persistable() to |
| * identify the region of code being persisted. |
| * |
| * @param[in] func_size The function to call to determine the size needed |
| * for persisted data. The \p file_offs parameter indicates the offset from the start |
| * of the persisted file where this data will reside (which is needed to |
| * calculate patch displacements). The callback can store a void* value into |
| * the address specified by \p user_data. This value will be passed to \p |
| * func_persist and if a patch callback is registered (see |
| * dr_register_persist_patch()) to \p func_patch. The same value will be |
| * shared with persisted code callbacks (see dr_register_persist_rx()) and |
| * read-only data callbacks (see dr_register_persist_ro()). |
| * @param[in] func_persist The function to call to write the actual data. |
| * Data to be persisted should be written to the file \p fd via |
| * dr_write_file(). The data will be writable when the persisted file is |
| * loaded back in for use. The return value of the function indicates success |
| * of the write. If the function returns false, the persisted cache file |
| * being generated will be abandoned under the assumption of a non-recoverable |
| * error. |
| * @param[in] func_resurrect The function to call to validate previously written data. |
| * The \p map variable points to the mapped-in data that was written at |
| * persist time. The return value of the function indicates success of the |
| * resurrection. If the function returns false, the persisted cache file |
| * being loaded will be abandoned under the assumption of a non-recoverable |
| * error. Any validation that the persisted file is suitable for use should |
| * be performed by the function prior to any restoration work needed for the |
| * data. The \p map address should be updated to point to the end of |
| * the persisted data (i.e., on return it should equal its start value plus |
| * the size that was passed to dr_register_persist_rw_size()). |
| * DR will perform self-consistency checks, including whether the |
| * whole pcache is present and that a checksum of at least part of |
| * the file matches, prior to calling this callback. Thus, the |
| * client can assume that it is not truncated. |
| * \note \p func_resurrect may be called during persisted file generation if |
| * a persisted file already exists, in order to merge with that file. |
| * \return whether successful. |
| */ |
| bool |
| dr_register_persist_rw( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * Unregister callback functions for storing writable data in a persisted cache file. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., one of the functions was not registered). |
| */ |
| bool |
| dr_unregister_persist_rw( |
| size_t (*func_size)(void *drcontext, void *perscxt, size_t file_offs, |
| void **user_data DR_PARAM_OUT), |
| bool (*func_persist)(void *drcontext, void *perscxt, file_t fd, void *user_data), |
| bool (*func_resurrect)(void *drcontext, void *perscxt, byte **map DR_PARAM_OUT)); |
| |
| DR_API |
| /** |
| * \warning This patching interface is in flux and is subject to |
| * change in the next release. Consider it experimental in this |
| * release. |
| * |
| * Registers a callback function for patching code prior to storing it in a |
| * persisted cache file. The length of each instruction cannot be changed, but |
| * displacements and offsets can be adjusted to make the code |
| * position-independent. A patch callback is only called once per persisted |
| * file, regardless of whether one or all of read-only, executable, or writable |
| * data has been added. Use the \p user_data parameter to pass the file offset |
| * or other data from the other persistence events to this one. |
| * |
| * @param[in] func_patch The function to call to perform any necessary |
| * patching of the to-be-persisted basic block code. The function |
| * should decode up to \p bb_size bytes from \p bb_start and look for call or |
| * jump displacements or rip-relative data references that need to |
| * be updated to use data in the persisted file. There is no padding |
| * between instructions, so a simple decode loop will find every instruction. |
| * The \p perscxt parameter can be passed to the routines |
| * dr_persist_start(), dr_persist_size(), and dr_fragment_persistable() to |
| * identify the region of code being persisted. |
| * \return whether successful. |
| */ |
| bool |
| dr_register_persist_patch(bool (*func_patch)(void *drcontext, void *perscxt, |
| byte *bb_start, size_t bb_size, |
| void *user_data)); |
| |
| DR_API |
| /** |
| * Unregister a callback function for patching persisted code. |
| * \return true if unregistration is successful and false if it is not |
| * (e.g., the function was not registered). |
| */ |
| bool |
| dr_unregister_persist_patch(bool (*func_patch)(void *drcontext, void *perscxt, |
| byte *bb_start, size_t bb_size, |
| void *user_data)); |
| |
| DR_API |
| /** |
| * Query whether detach is in progress. This is useful for clients that want to |
| * avoid the cost of resetting their global state on exit if there is no |
| * detaching and thus no chance of re-attaching. |
| */ |
| bool |
| dr_is_detaching(void); |
| |
| #endif /* _DR_EVENTS_H_ */ |