| /* ********************************************************** |
| * Copyright (c) 2010-2014 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 */ |
| |
| /* |
| * instrument.h - interface for instrumentation |
| */ |
| |
| #ifndef _INSTRUMENT_H_ |
| #define _INSTRUMENT_H_ 1 |
| |
| #include "../globals.h" |
| #include "../module_shared.h" |
| #include "arch.h" |
| #include "instr.h" |
| #include "dr_config.h" |
| |
| /* xref _USES_DR_VERSION_ in dr_api.h (PR 250952) and compatibility |
| * check in instrument.c (OLDEST_COMPATIBLE_VERSION, etc.). |
| * this is defined outside of CLIENT_INTERFACE b/c it's used for |
| * a general tracedump version as well. |
| */ |
| #define CURRENT_API_VERSION VERSION_NUMBER_INTEGER |
| |
| #ifdef CLIENT_INTERFACE |
| |
| /* DR_API EXPORT TOFILE dr_events.h */ |
| /* DR_API EXPORT BEGIN */ |
| #ifdef API_EXPORT_ONLY |
| #include "dr_config.h" |
| #endif |
| |
| /************************************************** |
| * ROUTINES TO REGISTER EVENT CALLBACKS |
| */ |
| /** |
| * @file dr_events.h |
| * @brief Event callback registration routines. |
| */ |
| /* DR_API EXPORT END */ |
| |
| 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_init() |
| * 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 EXPORT TOFILE dr_events.h */ |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * 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 EXPORT END */ |
| |
| 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. |
| * |
| * \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 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. |
| * - 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. |
| * |
| * \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)); |
| |
| #ifdef CUSTOM_TRACES |
| /* DR_API EXPORT BEGIN */ |
| |
| /** |
| * 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 EXPORT END */ |
| |
| 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)); |
| #endif |
| |
| /* 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. |
| * |
| * 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)); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * 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. 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; |
| } 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 EXPORT END */ |
| |
| 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. |
| * |
| * 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)); |
| |
| /* DR_API EXPORT TOFILE dr_events.h */ |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * 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 EXPORT END */ |
| |
| 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); |
| |
| #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. The \p loaded |
| * parameter indicates whether the module is about to be loaded (the |
| * normal case) or is already loaded (if the module was already there |
| * at the time DR initialized). \note The client should be aware that |
| * if the module is being loaded it may not be fully processed by the |
| * loader (relocating, rebinding and on Linux segment remapping may |
| * have not yet 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(). |
| */ |
| 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). |
| */ |
| 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)); |
| |
| /* DR_API EXPORT BEGIN */ |
| #ifdef WINDOWS |
| /* DR_API EXPORT END */ |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * 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 EXPORT END */ |
| |
| 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)); |
| /* DR_API EXPORT BEGIN */ |
| #endif /* WINDOWS */ |
| /* DR_API EXPORT END */ |
| |
| |
| 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()). |
| * |
| * 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. 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)); |
| |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| #ifdef UNIX |
| /* DR_API EXPORT END */ |
| |
| /* FIXME: 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. |
| * Xref PR 371339: we will need to not include it through signal.h but |
| * instead something like this: |
| * # define __need_siginfo_t |
| * # include <bits/siginfo.h> |
| */ |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * 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. |
| */ |
| DR_SIGNAL_REDIRECT, |
| } dr_signal_action_t; |
| /* DR_API EXPORT END */ |
| |
| 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)); |
| /* DR_API EXPORT BEGIN */ |
| #endif /* UNIX */ |
| /* DR_API EXPORT END */ |
| |
| |
| /**************************************************************************** |
| * SECURITY SUPPORT |
| */ |
| |
| #ifdef PROGRAM_SHEPHERDING |
| /* DR_API EXPORT BEGIN */ |
| |
| /** 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 EXPORT END */ |
| |
| 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 |
| * nudgeunix 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_init(). |
| */ |
| 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 |
| |
| void instrument_load_client_libs(void); |
| void instrument_init(void); |
| void instrument_exit(void); |
| bool is_in_client_lib(app_pc addr); |
| bool get_client_bounds(client_id_t client_id, |
| app_pc *start/*OUT*/, app_pc *end/*OUT*/); |
| const char *get_client_path_from_addr(app_pc addr); |
| bool is_valid_client_id(client_id_t id); |
| void instrument_client_thread_init(dcontext_t *dcontext, bool client_thread); |
| void instrument_thread_init(dcontext_t *dcontext, bool client_thread, bool valid_mc); |
| void instrument_thread_exit_event(dcontext_t *dcontext); |
| void instrument_thread_exit(dcontext_t *dcontext); |
| #ifdef UNIX |
| void instrument_fork_init(dcontext_t *dcontext); |
| #endif |
| bool instrument_basic_block(dcontext_t *dcontext, app_pc tag, instrlist_t *bb, |
| bool for_trace, bool translating, |
| dr_emit_flags_t *emitflags); |
| dr_emit_flags_t instrument_trace(dcontext_t *dcontext, app_pc tag, instrlist_t *trace, |
| bool translating); |
| #ifdef CUSTOM_TRACES |
| dr_custom_trace_action_t instrument_end_trace(dcontext_t *dcontext, app_pc trace_tag, |
| app_pc next_tag); |
| #endif |
| void instrument_fragment_deleted(dcontext_t *dcontext, app_pc tag, uint flags); |
| bool instrument_restore_state(dcontext_t *dcontext, bool restore_memory, |
| dr_restore_state_info_t *info); |
| |
| module_data_t * copy_module_area_to_module_data(const module_area_t *area); |
| void instrument_module_load_trigger(app_pc modbase); |
| void instrument_module_load(module_data_t *data, bool previously_loaded); |
| void instrument_module_unload(module_data_t *data); |
| |
| /* returns whether this sysnum should be intercepted */ |
| bool instrument_filter_syscall(dcontext_t *dcontext, int sysnum); |
| /* returns whether this syscall should execute */ |
| bool instrument_pre_syscall(dcontext_t *dcontext, int sysnum); |
| void instrument_post_syscall(dcontext_t *dcontext, int sysnum); |
| bool instrument_invoke_another_syscall(dcontext_t *dcontext); |
| |
| void instrument_nudge(dcontext_t *dcontext, client_id_t id, uint64 arg); |
| #ifdef WINDOWS |
| bool instrument_exception(dcontext_t *dcontext, dr_exception_t *exception); |
| void wait_for_outstanding_nudges(void); |
| #else |
| dr_signal_action_t instrument_signal(dcontext_t *dcontext, dr_siginfo_t *siginfo); |
| bool dr_signal_hook_exists(void); |
| #endif |
| int get_num_client_threads(void); |
| #ifdef PROGRAM_SHEPHERDING |
| void instrument_security_violation(dcontext_t *dcontext, app_pc target_pc, |
| security_violation_t violation, action_type_t *action); |
| #endif |
| |
| #endif /* CLIENT_INTERFACE */ |
| bool dr_get_mcontext_priv(dcontext_t *dcontext, dr_mcontext_t *dmc, priv_mcontext_t *mc); |
| #ifdef CLIENT_INTERFACE |
| |
| void instrument_client_lib_loaded(byte *start, byte *end); |
| void instrument_client_lib_unloaded(byte *start, byte *end); |
| |
| bool dr_bb_hook_exists(void); |
| bool dr_trace_hook_exists(void); |
| bool dr_fragment_deleted_hook_exists(void); |
| bool dr_end_trace_hook_exists(void); |
| bool dr_thread_exit_hook_exists(void); |
| bool dr_exit_hook_exists(void); |
| bool dr_xl8_hook_exists(void); |
| bool hide_tag_from_client(app_pc tag); |
| |
| uint instrument_persist_ro_size(dcontext_t *dcontext, void *perscxt, size_t file_offs); |
| bool instrument_persist_ro(dcontext_t *dcontext, void *perscxt, file_t fd); |
| bool instrument_resurrect_ro(dcontext_t *dcontext, void *perscxt, byte *map); |
| uint instrument_persist_rx_size(dcontext_t *dcontext, void *perscxt, size_t file_offs); |
| bool instrument_persist_rx(dcontext_t *dcontext, void *perscxt, file_t fd); |
| bool instrument_resurrect_rx(dcontext_t *dcontext, void *perscxt, byte *map); |
| uint instrument_persist_rw_size(dcontext_t *dcontext, void *perscxt, size_t file_offs); |
| bool instrument_persist_rw(dcontext_t *dcontext, void *perscxt, file_t fd); |
| bool instrument_resurrect_rw(dcontext_t *dcontext, void *perscxt, byte *map); |
| bool instrument_persist_patch(dcontext_t *dcontext, void *perscxt, |
| byte *bb_start, size_t bb_size); |
| |
| /* DR_API EXPORT TOFILE dr_tools.h */ |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * TOP-LEVEL ROUTINES |
| */ |
| /** |
| * @file dr_tools.h |
| * @brief Main API routines, including transparency support. |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Creates a DR context that can be used in a standalone program. |
| * \warning This context cannot be used as the drcontext for a thread |
| * running under DR control! It is only for standalone programs that |
| * wish to use DR as a library of disassembly, etc. routines. |
| * \return NULL on failure, such as running on an unsupported operating |
| * system version. |
| */ |
| void * |
| dr_standalone_init(void); |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| #ifdef API_EXPORT_ONLY |
| /** |
| * Use this dcontext for use with the standalone static decoder library. |
| * Pass it whenever a decoding-related API routine asks for a context. |
| */ |
| #define GLOBAL_DCONTEXT ((void *)-1) |
| #endif |
| |
| /************************************************** |
| * UTILITY ROUTINES |
| */ |
| |
| #ifdef WINDOWS |
| /** |
| * If \p x is false, displays a message about an assertion failure |
| * (appending \p msg to the message) and then calls dr_abort() |
| */ |
| # define DR_ASSERT_MSG(x, msg) \ |
| ((void)((!(x)) ? \ |
| (dr_messagebox("ASSERT FAILURE: %s:%d: %s (%s)", __FILE__, __LINE__, #x, msg),\ |
| dr_abort(), 0) : 0)) |
| #else |
| # define DR_ASSERT_MSG(x, msg) \ |
| ((void)((!(x)) ? \ |
| (dr_fprintf(STDERR, "ASSERT FAILURE: %s:%d: %s (%s)", \ |
| __FILE__, __LINE__, #x, msg), \ |
| dr_abort(), 0) : 0)) |
| #endif |
| |
| /** |
| * If \p x is false, displays a message about an assertion failure and |
| * then calls dr_abort() |
| */ |
| #define DR_ASSERT(x) DR_ASSERT_MSG(x, "") |
| |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** Returns true if all DynamoRIO caches are thread private. */ |
| bool |
| dr_using_all_private_caches(void); |
| |
| DR_API |
| /** \deprecated Replaced by dr_set_process_exit_behavior() */ |
| void |
| dr_request_synchronized_exit(void); |
| |
| DR_API |
| /** |
| * Returns the client-specific option string specified at client |
| * registration. \p client_id is the client ID passed to dr_init(). |
| */ |
| const char * |
| dr_get_options(client_id_t client_id); |
| |
| DR_API |
| /** |
| * Read the value of a string DynamoRIO runtime option named \p option_name into |
| * \p buf. Options are listed in \ref sec_options. DynamoRIO has many other |
| * undocumented options which may be queried through this API, but they are not |
| * officially supported. The option value is truncated to \p len bytes and |
| * null-terminated. |
| * \return false if no option named \p option_name exists, and true otherwise. |
| */ |
| bool |
| dr_get_string_option(const char *option_name, char *buf OUT, size_t len); |
| |
| DR_API |
| /** |
| * Read the value of an integer DynamoRIO runtime option named \p option_name |
| * into \p val. This includes boolean options. Options are listed in \ref |
| * sec_options. DynamoRIO has many other undocumented options which may be |
| * queried through this API, but they are not officially supported. |
| * \warning Always pass a full uint64 for \p val even if the option is a smaller |
| * integer to avoid overwriting nearby data. |
| * \return false if no option named \p option_name exists, and true otherwise. |
| */ |
| bool |
| dr_get_integer_option(const char *option_name, uint64 *val OUT); |
| |
| DR_API |
| /** |
| * Returns the client library name and path that were originally specified |
| * to load the library. If the resulting string is longer than #MAXIMUM_PATH |
| * it will be truncated. \p client_id is the client ID passed to a client's |
| * dr_init() function. |
| */ |
| const char * |
| dr_get_client_path(client_id_t client_id); |
| |
| DR_API |
| /** |
| * Returns the base address of the client library. \p client_id is |
| * the client ID passed to a client's dr_init() function. |
| */ |
| byte * |
| dr_get_client_base(client_id_t client_id); |
| |
| DR_API |
| /** |
| * Sets information presented to users in diagnostic messages. |
| * Only one name is supported, regardless of how many clients are in use. |
| * If this routine is called a second time, the new values supersede |
| * the original. |
| * The \p report_URL is meant to be a bug tracker location where users |
| * should go to report errors in the client end-user tool. |
| */ |
| bool |
| dr_set_client_name(const char *name, const char *report_URL); |
| |
| DR_API |
| /** Returns the image name (without path) of the current application. */ |
| const char * |
| dr_get_application_name(void); |
| |
| DR_API |
| /** Returns the process id of the current process. */ |
| process_id_t |
| dr_get_process_id(void); |
| |
| #ifdef UNIX |
| DR_API |
| /** |
| * Returns the process id of the parent of the current process. |
| * \note Linux only. |
| */ |
| process_id_t |
| dr_get_parent_id(void); |
| #endif |
| |
| /* DR_API EXPORT BEGIN */ |
| #ifdef WINDOWS |
| |
| /** Windows versions */ |
| /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx */ |
| typedef enum { |
| /** Windows 8.1 */ |
| DR_WINDOWS_VERSION_8_1 = 63, |
| /** Windows Server 2012 R2 */ |
| DR_WINDOWS_VERSION_2012_R2 = DR_WINDOWS_VERSION_8_1, |
| /** Windows 8 */ |
| DR_WINDOWS_VERSION_8 = 62, |
| /** Windows Server 2012 */ |
| DR_WINDOWS_VERSION_2012 = DR_WINDOWS_VERSION_8, |
| /** Windows 7 */ |
| DR_WINDOWS_VERSION_7 = 61, |
| /** Windows Server 2008 R2 */ |
| DR_WINDOWS_VERSION_2008_R2 = DR_WINDOWS_VERSION_7, |
| /** Windows Vista */ |
| DR_WINDOWS_VERSION_VISTA = 60, |
| /** Windows Server 2008 */ |
| DR_WINDOWS_VERSION_2008 = DR_WINDOWS_VERSION_VISTA, |
| /** Windows Server 2003 */ |
| DR_WINDOWS_VERSION_2003 = 52, |
| /** Windows XP 64-bit */ |
| DR_WINDOWS_VERSION_XP_X64 = DR_WINDOWS_VERSION_2003, |
| /** Windows XP */ |
| DR_WINDOWS_VERSION_XP = 51, |
| /** Windows 2000 */ |
| DR_WINDOWS_VERSION_2000 = 50, |
| /** Windows NT */ |
| DR_WINDOWS_VERSION_NT = 40, |
| } dr_os_version_t; |
| |
| /** Data structure used with dr_get_os_version() */ |
| typedef struct _dr_os_version_info_t { |
| /** The size of this structure. Set this to sizeof(dr_os_version_info_t). */ |
| size_t size; |
| /** The operating system version */ |
| dr_os_version_t version; |
| /** The service pack major number */ |
| uint service_pack_major; |
| /** The service pack minor number */ |
| uint service_pack_minor; |
| } dr_os_version_info_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Returns information about the version of the operating system. |
| * Returns whether successful. \note Windows only. \note The Windows |
| * API routine GetVersionEx may hide distinctions between versions, |
| * such as between Windows 8 and Windows 8.1. DR reports the true |
| * low-level version. |
| * |
| */ |
| bool |
| dr_get_os_version(dr_os_version_info_t *info); |
| |
| DR_API |
| /** |
| * Returns true if this process is a 32-bit process operating on a |
| * 64-bit Windows kernel, known as Windows-On-Windows-64, or WOW64. |
| * Returns false otherwise. \note Windows only. |
| */ |
| bool |
| dr_is_wow64(void); |
| |
| DR_API |
| /** |
| * Returns a pointer to the application's Process Environment Block |
| * (PEB). DR swaps to a private PEB when running client code, in |
| * order to isolate the client and its dependent libraries from the |
| * application, so conventional methods of reading the PEB will obtain |
| * the private PEB instead of the application PEB. \note Windows only. |
| */ |
| void * |
| dr_get_app_PEB(void); |
| |
| DR_API |
| /** |
| * Converts a process handle to a process id. |
| * \return Process id if successful; INVALID_PROCESS_ID on failure. |
| * \note Windows only. |
| */ |
| process_id_t |
| dr_convert_handle_to_pid(HANDLE process_handle); |
| |
| DR_API |
| /** |
| * Converts a process id to a process handle. |
| * \return Process handle if successful; INVALID_HANDLE_VALUE on failure. |
| * \note Windows only. |
| */ |
| HANDLE |
| dr_convert_pid_to_handle(process_id_t pid); |
| |
| /* DR_API EXPORT BEGIN */ |
| #endif |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** Retrieves the current time. */ |
| void |
| dr_get_time(dr_time_t *time); |
| |
| DR_API |
| /** |
| * Returns the number of milliseconds since Jan 1, 1601 (this is |
| * the current UTC time). |
| * |
| * \note This is the Windows standard. UNIX time functions typically |
| * count from the Epoch (Jan 1, 1970). The Epoch is 11644473600*1000 |
| * milliseconds after Jan 1, 1601. |
| */ |
| uint64 |
| dr_get_milliseconds(void); |
| |
| DR_API |
| /** |
| * Returns a pseudo-random number in the range [0..max). |
| * The pseudo-random sequence can be repeated by passing the seed |
| * used during a run to the next run via the -prng_seed runtime option. |
| */ |
| uint |
| dr_get_random_value(uint max); |
| |
| DR_API |
| /** |
| * Sets the seed used for dr_get_random_value(). Generally this would |
| * only be called during client initialization. |
| */ |
| void |
| dr_set_random_seed(uint seed); |
| |
| DR_API |
| /** Returns the seed used for dr_get_random_value(). */ |
| uint |
| dr_get_random_seed(void); |
| |
| DR_API |
| /** |
| * Aborts the process immediately without any cleanup (i.e., the exit event |
| * will not be called). |
| */ |
| void |
| dr_abort(void); |
| |
| DR_API |
| /** |
| * Exits the process, first performing a full cleanup that will |
| * trigger the exit event (dr_register_exit_event()). The process |
| * exit code is set to \p exit_code. |
| * |
| * On Linux, only the bottom 8 bits of \p exit_code will be honored |
| * for a normal exit. If bits 9..16 are not all zero, DR will send an |
| * unhandled signal of that signal number instead of performing a normal |
| * exit. |
| * |
| * \note Calling this from \p dr_init or from the primary thread's |
| * initialization event is not guaranteed to always work, as DR may |
| * invoke a thread exit event where a thread init event was never |
| * called. We recommend using dr_abort() or waiting for full |
| * initialization prior to use of this routine. |
| */ |
| void |
| dr_exit_process(int exit_code); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** Indicates the type of memory dump for dr_create_memory_dump(). */ |
| typedef enum { |
| /** |
| * A "livedump", or "ldmp", DynamoRIO's own custom memory dump format. |
| * The ldmp format does not currently support specifying a context |
| * for the calling thread, so it will always include the call frames |
| * to dr_create_memory_dump(). The \p ldmp.exe tool can be used to |
| * create a dummy process (using the \p dummy.exe executable) which |
| * can then be attached to by the debugger (use a non-invasive attach) |
| * in order to view the memory dump contents. |
| * |
| * \note Windows only. |
| */ |
| DR_MEMORY_DUMP_LDMP = 0x0001, |
| } dr_memory_dump_flags_t; |
| |
| /** Indicates the type of memory dump for dr_create_memory_dump(). */ |
| typedef struct _dr_memory_dump_spec_t { |
| /** The size of this structure. Set this to sizeof(dr_memory_dump_spec_t). */ |
| size_t size; |
| /** The type of memory dump requested. */ |
| dr_memory_dump_flags_t flags; |
| /** |
| * This field only applies to DR_MEMORY_DUMP_LDMP. This string is |
| * stored inside the ldmp as the reason for the dump. |
| */ |
| const char *label; |
| /** |
| * This field only applies to DR_MEMORY_DUMP_LDMP. This is an optional output |
| * field that, if non-NULL, will be written with the path to the created file. |
| */ |
| char *ldmp_path; |
| /** |
| * This field only applies to DR_MEMORY_DUMP_LDMP. This is the maximum size, |
| * in bytes, of ldmp_path. |
| */ |
| size_t ldmp_path_size; |
| } dr_memory_dump_spec_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Requests that DR create a memory dump file of the current process. |
| * The type of dump is specified by \p spec. |
| * |
| * \return whether successful. |
| * |
| * \note this function is only supported on Windows for now. |
| */ |
| bool |
| dr_create_memory_dump(dr_memory_dump_spec_t *spec); |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * APPLICATION-INDEPENDENT MEMORY ALLOCATION |
| */ |
| |
| /** Flags used with dr_custom_alloc() */ |
| typedef enum { |
| /** |
| * If this flag is not specified, dr_custom_alloc() uses a managed |
| * heap to allocate the memory, just like dr_thread_alloc() or |
| * dr_global_alloc(). In that case, it ignores any requested |
| * protection bits (\p prot parameter), and the location (\p addr |
| * parameter) must be NULL. If this flag is specified, a |
| * page-aligned, separate block of memory is allocated, in a |
| * similar fashion to dr_nonheap_alloc(). |
| */ |
| DR_ALLOC_NON_HEAP = 0x0001, |
| /** |
| * This flag only applies to heap memory (i.e., when |
| * #DR_ALLOC_NON_HEAP is not specified). If this flag is not |
| * specified, global heap is used (just like dr_global_alloc()) |
| * and the \p drcontext parameter is ignored. If it is specified, |
| * thread-private heap specific to \p drcontext is used, just like |
| * dr_thread_alloc(). |
| */ |
| DR_ALLOC_THREAD_PRIVATE = 0x0002, |
| /** |
| * Allocate memory that is 32-bit-displacement reachable from the |
| * code caches and from the client library. Memory allocated |
| * through dr_thread_alloc(), dr_global_alloc(), and |
| * dr_nonheap_alloc() is also reachable, but for |
| * dr_custom_alloc(), the resulting memory is not reachable unless |
| * this flag is specified. If this flag is passed, the requested |
| * location (\p addr parameter) must be NULL. This flag is not |
| * compatible with #DR_ALLOC_LOW_2GB, #DR_ALLOC_FIXED_LOCATION, or |
| * #DR_ALLOC_NON_DR. |
| */ |
| DR_ALLOC_CACHE_REACHABLE = 0x0004, |
| /** |
| * This flag only applies to non-heap memory (i.e., when |
| * #DR_ALLOC_NON_HEAP is specified). The flag requests that |
| * memory be allocated at a specific address, given in the \p addr |
| * parameter. Without this flag, the \p addr parameter is not |
| * honored. This flag is not compatible with #DR_ALLOC_LOW_2GB or |
| * #DR_ALLOC_CACHE_REACHABLE. |
| */ |
| DR_ALLOC_FIXED_LOCATION = 0x0008, |
| /** |
| * This flag only applies to non-heap memory (i.e., when |
| * #DR_ALLOC_NON_HEAP is specified) in 64-bit mode. The flag |
| * requests that memory be allocated in the low 2GB of the address |
| * space. If this flag is passed, the requested location (\p addr |
| * parameter) must be NULL. This flag is not compatible with |
| * #DR_ALLOC_FIXED_LOCATION. |
| */ |
| DR_ALLOC_LOW_2GB = 0x0010, |
| /** |
| * This flag only applies to non-heap memory (i.e., when |
| * #DR_ALLOC_NON_HEAP is specified). When this flag is specified, |
| * the allocated memory is not considered to be DynamoRIO or tool |
| * memory and thus is not kept separate from the application. |
| * This is similar to dr_raw_mem_alloc(). Use of this memory is |
| * at the client's own risk. This flag is not compatible with |
| * #DR_ALLOC_CACHE_REACHABLE. |
| */ |
| DR_ALLOC_NON_DR = 0x0020, |
| #ifdef WINDOWS |
| /** |
| * This flag only applies to non-heap, non-DR memory (i.e., when |
| * both #DR_ALLOC_NON_HEAP and #DR_ALLOC_NON_DR are specified) on |
| * Windows. When this flag is specified, the allocated memory is |
| * reserved but not committed, just like the MEM_RESERVE Windows API |
| * flag (the default is MEM_RESERVE|MEM_COMMIT). |
| */ |
| DR_ALLOC_RESERVE_ONLY = 0x0040, |
| /** |
| * This flag only applies to non-heap, non-DR memory (i.e., when both |
| * #DR_ALLOC_NON_HEAP and #DR_ALLOC_NON_DR are specified) on Windows. |
| * This flag must be combined with DR_ALLOC_FIXED_LOCATION. When this |
| * flag is specified, previously allocated memory is committed, just |
| * like the MEM_COMMIT Windows API flag (when this flag is not passed, |
| * the effect is MEM_RESERVE|MEM_COMMIT). When passed to |
| * dr_custom_free(), this flag causes a de-commit, just like the |
| * MEM_DECOMMIT Windows API flag. This flag cannot be combined with |
| * #DR_ALLOC_LOW_2GB and must include a non-NULL requested location (\p |
| * addr parameter). |
| */ |
| DR_ALLOC_COMMIT_ONLY = 0x0080, |
| #endif |
| } dr_alloc_flags_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Allocates \p size bytes of memory from DR's memory pool specific to the |
| * thread associated with \p drcontext. |
| */ |
| void * |
| dr_thread_alloc(void *drcontext, size_t size); |
| |
| DR_API |
| /** |
| * Frees thread-specific memory allocated by dr_thread_alloc(). |
| * \p size must be the same as that passed to dr_thread_alloc(). |
| */ |
| void |
| dr_thread_free(void *drcontext, void *mem, size_t size); |
| |
| DR_API |
| /** Allocates \p size bytes of memory from DR's global memory pool. */ |
| void * |
| dr_global_alloc(size_t size); |
| |
| DR_API |
| /** |
| * Frees memory allocated by dr_global_alloc(). |
| * \p size must be the same as that passed to dr_global_alloc(). |
| */ |
| void |
| dr_global_free(void *mem, size_t size); |
| |
| DR_API |
| /** |
| * Allocates memory with the properties requested by \p flags. |
| * |
| * If \p addr is non-NULL (only allowed with certain flags), it must |
| * be page-aligned. |
| * |
| * To make more space available for the code caches when running |
| * larger applications, or for clients that use a lot of heap memory |
| * that is not directly referenced from the cache, we recommend that |
| * dr_custom_alloc() be called to obtain memory that is not guaranteed |
| * to be reachable from the code cache (by not passing |
| * #DR_ALLOC_CACHE_REACHABLE). This frees up space in the reachable |
| * region. |
| * |
| * Returns NULL on failure. |
| */ |
| void * |
| dr_custom_alloc(void *drcontext, dr_alloc_flags_t flags, size_t size, |
| uint prot, void *addr); |
| |
| DR_API |
| /** |
| * Frees memory allocated by dr_custom_alloc(). The same \p flags |
| * and \p size must be passed here as were passed to dr_custom_alloc(). |
| */ |
| bool |
| dr_custom_free(void *drcontext, dr_alloc_flags_t flags, void *addr, size_t size); |
| |
| DR_API |
| /** |
| * Allocates \p size bytes of memory as a separate allocation from DR's |
| * heap, allowing for separate protection. |
| * The \p prot protection should use the DR_MEMPROT_READ, |
| * DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits. |
| * When creating a region to hold dynamically generated code, use |
| * this routine in order to create executable memory. |
| */ |
| void * |
| dr_nonheap_alloc(size_t size, uint prot); |
| |
| DR_API |
| /** |
| * Frees memory allocated by dr_nonheap_alloc(). |
| * \p size must be the same as that passed to dr_nonheap_alloc(). |
| */ |
| void |
| dr_nonheap_free(void *mem, size_t size); |
| |
| DR_API |
| /** |
| * \warning This raw memory allocation interface is in flux and is subject to |
| * change in the next release. Consider it experimental in this release. |
| * |
| * Allocates \p size bytes (page size aligned) of memory as a separate |
| * allocation at preferred base \p addr that must be page size aligned, |
| * allowing for separate protection. |
| * If \p addr is NULL, an arbitrary address is picked. |
| * |
| * The \p prot protection should use the DR_MEMPROT_READ, |
| * DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits. |
| * The allocated memory is not considered to be DynamoRIO or tool memory and |
| * thus is not kept separate from the application. Use of this memory is at the |
| * client's own risk. |
| * |
| * Returns the actual address allocated or NULL if memory allocation at |
| * preferred base fails. |
| */ |
| void * |
| dr_raw_mem_alloc(size_t size, uint prot, void *addr); |
| |
| DR_API |
| /** |
| * Frees memory allocated by dr_raw_mem_alloc(). |
| * \p addr and \p size must be the same as that passed to dr_raw_mem_alloc() |
| * on Windows. |
| */ |
| bool |
| dr_raw_mem_free(void *addr, size_t size); |
| |
| #ifdef LINUX |
| DR_API |
| /** |
| * Calls mremap with the specified parameters and returns the result. |
| * The old memory must be non-DR memory, and the new memory is also |
| * considered to be non-DR memory (see #DR_ALLOC_NON_DR). |
| * \note Linux-only. |
| */ |
| void * |
| dr_raw_mremap(void *old_address, size_t old_size, size_t new_size, |
| int flags, void *new_address); |
| |
| DR_API |
| /** |
| * Sets the program break to the specified value. Invokes the SYS_brk |
| * system call and returns the result. This is the application's |
| * program break, so use this system call only when deliberately |
| * changing the application's behavior. |
| * \note Linux-only. |
| */ |
| void * |
| dr_raw_brk(void *new_address); |
| #endif |
| |
| |
| #ifdef UNIX |
| DR_API |
| /** |
| * Allocates memory from DR's global memory pool, but mimics the |
| * behavior of malloc. Memory must be freed with __wrap_free(). The |
| * __wrap routines are intended to be used with ld's -wrap option to |
| * replace a client's use of malloc, realloc, and free with internal |
| * versions that allocate memory from DR's private pool. With -wrap, |
| * clients can link to libraries that allocate heap memory without |
| * interfering with application allocations. |
| * \note Currently Linux only. |
| */ |
| void * |
| __wrap_malloc(size_t size); |
| |
| DR_API |
| /** |
| * Reallocates memory from DR's global memory pool, but mimics the |
| * behavior of realloc. Memory must be freed with __wrap_free(). The |
| * __wrap routines are intended to be used with ld's -wrap option; see |
| * __wrap_malloc() for more information. |
| * \note Currently Linux only. |
| */ |
| void * |
| __wrap_realloc(void *mem, size_t size); |
| |
| DR_API |
| /** |
| * Allocates memory from DR's global memory pool, but mimics the |
| * behavior of calloc. Memory must be freed with __wrap_free(). The |
| * __wrap routines are intended to be used with ld's -wrap option; see |
| * __wrap_malloc() for more information. |
| * \note Currently Linux only. |
| */ |
| void * |
| __wrap_calloc(size_t nmemb, size_t size); |
| |
| DR_API |
| /** |
| * Frees memory from DR's global memory pool. Memory must have been |
| * allocated with __wrap_malloc(). The __wrap routines are intended to |
| * be used with ld's -wrap option; see __wrap_malloc() for more |
| * information. |
| * \note Currently Linux only. |
| */ |
| void |
| __wrap_free(void *mem); |
| #endif |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * MEMORY QUERY/ACCESS ROUTINES |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Checks to see that all bytes with addresses in the range [\p pc, \p pc + \p size - 1] |
| * are readable and that reading from that range won't generate an exception (see also |
| * dr_safe_read() and DR_TRY_EXCEPT()). |
| * \note Nothing guarantees that the memory will stay readable for any length of time. |
| * \note On Linux, especially if the app is in the middle of loading a library |
| * and has not properly set up the .bss yet, a page that seems readable can still |
| * generate SIGBUS if beyond the end of an mmapped file. Use dr_safe_read() or |
| * DR_TRY_EXCEPT() to avoid such problems. |
| */ |
| bool |
| dr_memory_is_readable(const byte *pc, size_t size); |
| |
| /* FIXME - this is a real view of memory including changes made for dr cache consistency, |
| * but what we really want to show the client is the apps view of memory (which would |
| * requires fixing correcting the view and fixing up exceptions for areas we made read |
| * only) - see PR 198873 */ |
| DR_API |
| /** |
| * An os neutral method for querying a memory address. Returns true |
| * iff a memory region containing \p pc is found. If found additional |
| * information about the memory region is returned in the optional out |
| * arguments \p base_pc, \p size, and \p prot where \p base_pc is the |
| * start address of the memory region continaing \p pc, \p size is the |
| * size of said memory region and \p prot is an ORed combination of |
| * DR_MEMPROT_* flags describing its current protection. |
| * |
| * \note To examine only application memory, skip memory for which |
| * dr_memory_is_dr_internal() or dr_memory_is_in_client() returns true. |
| * |
| * \note DR may mark writable code pages as read-only but pretend they're |
| * writable. When this happens, it will include both #DR_MEMPROT_WRITE |
| * and #DR_MEMPROT_PRETEND_WRITE in \p prot. |
| */ |
| bool |
| dr_query_memory(const byte *pc, byte **base_pc, size_t *size, uint *prot); |
| |
| DR_API |
| /** |
| * Provides additional information beyond dr_query_memory(). |
| * Returns true if it was able to obtain information (including about |
| * free regions) and sets the fields of \p info. This routine can be |
| * used to iterate over the entire address space. Such an iteration |
| * should stop on reaching the top of the address space, or on |
| * reaching kernel memory (look for #DR_MEMTYPE_ERROR_WINKERNEL) on |
| * Windows. |
| * |
| * Returns false on failure and sets info->type to a DR_MEMTYPE_ERROR* |
| * code indicating the reason for failure. |
| * |
| * \note To examine only application memory, skip memory for which |
| * dr_memory_is_dr_internal() returns true. |
| * |
| * \note DR may mark writable code pages as read-only but pretend they're |
| * writable. When this happens, it will include both #DR_MEMPROT_WRITE |
| * and #DR_MEMPROT_PRETEND_WRITE in \p info->prot. |
| */ |
| bool |
| dr_query_memory_ex(const byte *pc, OUT dr_mem_info_t *info); |
| |
| /* DR_API EXPORT BEGIN */ |
| #ifdef WINDOWS |
| /* DR_API EXPORT END */ |
| DR_API |
| /** |
| * Equivalent to the win32 API function VirtualQuery(). |
| * See that routine for a description of |
| * arguments and return values. \note Windows only. |
| * |
| * \note DR may mark writable code pages as read-only but pretend they're |
| * writable. When this happens, this routine will indicate that the |
| * memory is writable. Call dr_query_memory() or dr_query_memory_ex() |
| * before attempting to write to application memory to ensure it's |
| * not read-only underneath. |
| */ |
| size_t |
| dr_virtual_query(const byte *pc, MEMORY_BASIC_INFORMATION *mbi, size_t mbi_size); |
| /* DR_API EXPORT BEGIN */ |
| #endif |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Safely reads \p size bytes from address \p base into buffer \p |
| * out_buf. Reading is done without the possibility of an exception |
| * occurring. Optionally returns the actual number of bytes copied |
| * into \p bytes_read. Returns true if successful. |
| * \note See also DR_TRY_EXCEPT(). |
| */ |
| bool |
| dr_safe_read(const void *base, size_t size, void *out_buf, size_t *bytes_read); |
| |
| DR_API |
| /** |
| * Safely writes \p size bytes from buffer \p in_buf to address \p |
| * base. Writing is done without the possibility of an exception |
| * occurring. Optionally returns the actual number of bytes copied |
| * into \p bytes_written. Returns true if successful. |
| * \note See also DR_TRY_EXCEPT(). |
| */ |
| bool |
| dr_safe_write(void *base, size_t size, const void *in_buf, size_t *bytes_written); |
| |
| DR_API |
| /** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */ |
| void |
| dr_try_setup(void *drcontext, void **try_cxt); |
| |
| DR_API |
| /** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */ |
| int |
| dr_try_start(void *buf); |
| |
| DR_API |
| /** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */ |
| void |
| dr_try_stop(void *drcontext, void *try_cxt); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * Simple try..except support for executing operations that might |
| * fault and recovering if they do. Be careful with this feature |
| * as it has some limitations: |
| * - do not use a return within a try statement (we do not have |
| * language support) |
| * - any automatic variables that you want to use in the except |
| * block should be declared volatile |
| * - no locks should be grabbed in a try statement (because |
| * there is no finally support to release them) |
| * - nesting is supported, but finally statements are not |
| * supported |
| * |
| * For fault-free reads in isolation, use dr_safe_read() instead. |
| * dr_safe_read() out-performs DR_TRY_EXCEPT. |
| * |
| * For fault-free writes in isolation, dr_safe_write() can be used, |
| * although on Windows it invokes a system call and can be less |
| * performant than DR_TRY_EXCEPT. |
| */ |
| #define DR_TRY_EXCEPT(drcontext, try_statement, except_statement) do {\ |
| void *try_cxt; \ |
| dr_try_setup(drcontext, &try_cxt); \ |
| if (dr_try_start(try_cxt) == 0) { \ |
| try_statement \ |
| dr_try_stop(drcontext, try_cxt); \ |
| } else { \ |
| /* roll back first in case except faults or returns */ \ |
| dr_try_stop(drcontext, try_cxt); \ |
| except_statement \ |
| } \ |
| } while (0) |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Modifies the memory protections of the region from \p start through |
| * \p start + \p size. Modification of memory allocated by DR or of |
| * the DR or client libraries themselves is allowed under the |
| * assumption that the client knows what it is doing. Modification of |
| * the ntdll.dll library on Windows is not allowed. Returns true if |
| * successful. |
| */ |
| bool |
| dr_memory_protect(void *base, size_t size, uint new_prot); |
| |
| DR_API |
| /** |
| * Returns true iff pc is memory allocated by DR for its own |
| * purposes, and would not exist if the application were run |
| * natively. |
| */ |
| bool |
| dr_memory_is_dr_internal(const byte *pc); |
| |
| DR_API |
| /** |
| * Returns true iff pc is located inside a client library, an Extension |
| * library used by a client, or an auxiliary client library (see |
| * dr_load_aux_library()). |
| */ |
| bool |
| dr_memory_is_in_client(const byte *pc); |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * CLIENT AUXILIARY LIBRARIES |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Loads the library with the given path as an auxiliary client |
| * library. The library is not treated as an application module but |
| * as an extension of DR. The library will be included in |
| * dr_memory_is_in_client() and any faults in the library will be |
| * considered client faults. The bounds of the loaded library are |
| * returned in the optional out variables. On failure, returns NULL. |
| * |
| * If only a filename and not a full path is given, this routine will |
| * search for the library in the standard search locations for DR's |
| * private loader. |
| */ |
| dr_auxlib_handle_t |
| dr_load_aux_library(const char *name, |
| byte **lib_start /*OPTIONAL OUT*/, |
| byte **lib_end /*OPTIONAL OUT*/); |
| |
| DR_API |
| /** |
| * Looks up the exported routine with the given name in the given |
| * client auxiliary library loaded by dr_load_aux_library(). Returns |
| * NULL on failure. |
| */ |
| dr_auxlib_routine_ptr_t |
| dr_lookup_aux_library_routine(dr_auxlib_handle_t lib, const char *name); |
| |
| DR_API |
| /** |
| * Unloads the given library, which must have been loaded by |
| * dr_load_aux_library(). Returns whether successful. |
| */ |
| bool |
| dr_unload_aux_library(dr_auxlib_handle_t lib); |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| #if defined(WINDOWS) && !defined(X64) |
| /* DR_API EXPORT END */ |
| DR_API |
| /** |
| * Similar to dr_load_aux_library(), but loads a 64-bit library for |
| * access from a 32-bit process running on a 64-bit Windows kernel. |
| * Fails if called from a 32-bit kernel or from a 64-bit process. |
| * The library will be located in the low part of the address space |
| * with 32-bit addresses. |
| * Functions in the library can be called with dr_invoke_x64_routine(). |
| * |
| * \warning Invoking 64-bit code is fragile. Currently, this routine |
| * uses the system loader, under the assumption that little isolation |
| * is needed versus application 64-bit state. Consider use of this routine |
| * experimental: use at your own risk! |
| * |
| * \note Windows only. |
| * |
| * \note Currently this routine does not support loading kernel32.dll |
| * or any library that depends on it. |
| * It also does not invoke the entry point for any dependent libraries |
| * loaded as part of loading \p name. |
| * |
| * \note Currently this routine does not support Windows 8. |
| */ |
| dr_auxlib64_handle_t |
| dr_load_aux_x64_library(const char *name); |
| |
| DR_API |
| /** |
| * Looks up the exported routine with the given name in the given |
| * 64-bit client auxiliary library loaded by dr_load_aux_x64_library(). Returns |
| * NULL on failure. |
| * The returned function can be called with dr_invoke_x64_routine(). |
| * |
| * \note Windows only. |
| * |
| * \note Currently this routine does not support Windows 8. |
| */ |
| dr_auxlib64_routine_ptr_t |
| dr_lookup_aux_x64_library_routine(dr_auxlib64_handle_t lib, const char *name); |
| |
| DR_API |
| /** |
| * Unloads the given library, which must have been loaded by |
| * dr_load_aux_x64_library(). Returns whether successful. |
| * |
| * \note Windows only. |
| */ |
| bool |
| dr_unload_aux_x64_library(dr_auxlib64_handle_t lib); |
| |
| DR_API |
| /** |
| * Must be called from 32-bit mode. Switches to 64-bit mode, calls \p |
| * func64 with the given parameters, switches back to 32-bit mode, and |
| * then returns to the caller. Requires that \p func64 be located in |
| * the low 4GB of the address space. All parameters must be 32-bit |
| * sized, and all are widened via sign-extension when passed to \p |
| * func64. |
| * |
| * \return -1 on failure; else returns the return value of \p func64. |
| * |
| * \warning Invoking 64-bit code is fragile. The WOW64 layer assumes |
| * there is no other 64-bit code that will be executed. |
| * dr_invoke_x64_routine() attempts to save the WOW64 state, but it |
| * has not been tested in all versions of WOW64. Also, invoking |
| * 64-bit code that makes callbacks is not supported, as not only a |
| * custom wrapper to call the 32-bit code in the right mode would be |
| * needed, but also a way to restore the WOW64 state in case the |
| * 32-bit callback makes a system call. Consider use of this routine |
| * experimental: use at your own risk! |
| * |
| * \note Windows only. |
| */ |
| int64 |
| dr_invoke_x64_routine(dr_auxlib64_routine_ptr_t func64, uint num_params, ...); |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| #endif /* WINDOWS && !X64 */ |
| /* DR_API EXPORT END */ |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * LOCK SUPPORT |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Initializes a mutex. |
| * |
| * Warning: there are restrictions on when DR-provided mutexes, and |
| * locks in general, can be held by a client: no lock should be held |
| * while application code is executing in the code cache. Locks can |
| * be used while inside client code reached from clean calls out of |
| * the code cache, but they must be released before returning to the |
| * cache. Failing to follow these restrictions can lead to deadlocks. |
| */ |
| void * |
| dr_mutex_create(void); |
| |
| DR_API |
| /** Deletes \p mutex. */ |
| void |
| dr_mutex_destroy(void *mutex); |
| |
| DR_API |
| /** Locks \p mutex. Waits until the mutex is successfully held. */ |
| void |
| dr_mutex_lock(void *mutex); |
| |
| DR_API |
| /** Unlocks \p mutex. Asserts that mutex is currently locked. */ |
| void |
| dr_mutex_unlock(void *mutex); |
| |
| DR_API |
| /** Tries once to lock \p mutex, returns whether or not successful. */ |
| bool |
| dr_mutex_trylock(void *mutex); |
| |
| DR_API |
| /** |
| * Returns true iff \p mutex is owned by the calling thread. |
| * This routine is only available in debug builds. |
| * In release builds it always returns true. |
| */ |
| bool |
| dr_mutex_self_owns(void *mutex); |
| |
| DR_API |
| /** |
| * Instructs DR to treat this lock as an application lock. Primarily |
| * this avoids debug-build checks that no DR locks are held in situations |
| * where locks are disallowed. |
| * |
| * \warning Any one lock should either be a DR lock or an application lock. |
| * Use this routine with caution and do not call it on a DR lock that is |
| * used in DR contexts, as it disables debug checks. |
| * |
| * \return whether successful. |
| */ |
| bool |
| dr_mutex_mark_as_app(void *mutex); |
| |
| DR_API |
| /** |
| * Creates and initializes a read-write lock. A read-write lock allows |
| * multiple readers or alternatively a single writer. The lock |
| * restrictions for mutexes apply (see dr_mutex_create()). |
| */ |
| void * |
| dr_rwlock_create(void); |
| |
| DR_API |
| /** Deletes \p rwlock. */ |
| void |
| dr_rwlock_destroy(void *rwlock); |
| |
| DR_API |
| /** Acquires a read lock on \p rwlock. */ |
| void |
| dr_rwlock_read_lock(void *rwlock); |
| |
| DR_API |
| /** Releases a read lock on \p rwlock. */ |
| void |
| dr_rwlock_read_unlock(void *rwlock); |
| |
| DR_API |
| /** Acquires a write lock on \p rwlock. */ |
| void |
| dr_rwlock_write_lock(void *rwlock); |
| |
| DR_API |
| /** Releases a write lock on \p rwlock. */ |
| void |
| dr_rwlock_write_unlock(void *rwlock); |
| |
| DR_API |
| /** Tries once to acquire a write lock on \p rwlock and returns whether successful. */ |
| bool |
| dr_rwlock_write_trylock(void *rwlock); |
| |
| DR_API |
| /** Returns whether the calling thread owns the write lock on \p rwlock. */ |
| bool |
| dr_rwlock_self_owns_write_lock(void *rwlock); |
| |
| DR_API |
| /** |
| * Instructs DR to treat this lock as an application lock. Primarily |
| * this avoids debug-build checks that no DR locks are held in situations |
| * where locks are disallowed. |
| * |
| * \warning Any one lock should either be a DR lock or an application lock. |
| * Use this routine with caution and do not call it on a DR lock that is |
| * used in DR contexts, as it disables debug checks. |
| * |
| * \return whether successful. |
| */ |
| bool |
| dr_rwlock_mark_as_app(void *rwlock); |
| |
| DR_API |
| /** |
| * Creates and initializes a recursive lock. A recursive lock allows |
| * the same thread to acquire it multiple times. The lock |
| * restrictions for mutexes apply (see dr_mutex_create()). |
| */ |
| void * |
| dr_recurlock_create(void); |
| |
| DR_API |
| /** Deletes \p reclock. */ |
| void |
| dr_recurlock_destroy(void *reclock); |
| |
| DR_API |
| /** Acquires \p reclock, or increments the ownership count if already owned. */ |
| void |
| dr_recurlock_lock(void *reclock); |
| |
| DR_API |
| /** Decrements the ownership count of \p reclock and releases if zero. */ |
| void |
| dr_recurlock_unlock(void *reclock); |
| |
| DR_API |
| /** Tries once to acquire \p reclock and returns whether successful. */ |
| bool |
| dr_recurlock_trylock(void *reclock); |
| |
| DR_API |
| /** Returns whether the calling thread owns \p reclock. */ |
| bool |
| dr_recurlock_self_owns(void *reclock); |
| |
| DR_API |
| /** |
| * Instructs DR to treat this lock as an application lock. Primarily |
| * this avoids debug-build checks that no DR locks are held in situations |
| * where locks are disallowed. |
| * |
| * \warning Any one lock should either be a DR lock or an application lock. |
| * Use this routine with caution and do not call it on a DR lock that is |
| * used in DR contexts, as it disables debug checks. |
| * |
| * \return whether successful. |
| */ |
| bool |
| dr_recurlock_mark_as_app(void *reclock); |
| |
| DR_API |
| /** |
| * Use this function to mark a region of code as safe for DR to suspend |
| * the client while inside the region. DR will not relocate the client |
| * from the region and will resume it at precisely the suspend point. |
| * |
| * This function must be used in client code that acquires application locks. |
| * Use this feature with care! Do not mark code as safe to suspend that has |
| * a code cache return point. I.e., do not call this routine from a clean |
| * call. |
| * |
| * No DR locks can be held while in a safe region. Consequently, do |
| * not call this routine from any DR event callback. It may only be used |
| * from natively executing code. |
| * |
| * Always invoke this routine in pairs, with the first passing true |
| * for \p enter and the second passing false, thus delimiting the |
| * region. |
| */ |
| bool |
| dr_mark_safe_to_suspend(void *drcontext, bool enter); |
| |
| DR_API |
| /** Atomically adds \p *x and \p val and returns the sum. */ |
| int |
| dr_atomic_add32_return_sum(volatile int *x, int val); |
| |
| /* DR_API EXPORT BEGIN */ |
| /************************************************** |
| * MODULE INFORMATION ROUTINES |
| */ |
| |
| /** For dr_module_iterator_* interface */ |
| typedef void * dr_module_iterator_t; |
| |
| #ifdef AVOID_API_EXPORT |
| /* We always give copies of the module_area_t information to clients (in the form |
| * of a module_data_t defined below) to avoid locking issues (see PR 225020). */ |
| /* i#160/PR 562667: support non-contiguous library mappings. While we're at |
| * it we go ahead and store info on each segment whether contiguous or not. |
| */ |
| #endif |
| #ifdef UNIX |
| /** Holds information on a segment of a loaded module. */ |
| typedef struct _module_segment_data_t { |
| app_pc start; /**< Start address of the segment, page-aligned backward. */ |
| app_pc end; /**< End address of the segment, page-aligned forward. */ |
| uint prot; /**< Protection attributes of the segment */ |
| } module_segment_data_t; |
| #endif |
| |
| /** |
| * Holds information about a loaded module. \note On Linux the start address can be |
| * cast to an Elf32_Ehdr or Elf64_Ehdr. \note On Windows the start address can be cast to |
| * an IMAGE_DOS_HEADER for use in finding the IMAGE_NT_HEADER and its OptionalHeader. |
| * The OptionalHeader can be used to walk the module sections (among other things). |
| * See WINNT.H. \note On MacOS the start address can be cast to mach_header or |
| * mach_header_64. |
| * \note When accessing any memory inside the module (including header fields) |
| * user is responsible for guarding against corruption and the possibility of the module |
| * being unmapped. |
| */ |
| struct _module_data_t { |
| union { |
| app_pc start; /**< starting address of this module */ |
| module_handle_t handle; /**< module_handle for use with dr_get_proc_address() */ |
| } ; /* anonymous union of start address and module handle */ |
| /** |
| * Ending address of this module. If the module is not contiguous |
| * (which is common on MacOS, and can happen on Linux), this is the |
| * highest address of the module, but there can be gaps in between start |
| * and end that are either unmapped or that contain other mappings or |
| * libraries. Use the segments array to examine each mapped region, |
| * and use dr_module_contains_addr() as a convenience routine, rather than |
| * checking against [start..end). |
| */ |
| app_pc end; |
| |
| app_pc entry_point; /**< entry point for this module as specified in the headers */ |
| |
| uint flags; /**< Reserved, set to 0 */ |
| |
| module_names_t names; /**< struct containing name(s) for this module; use |
| * dr_module_preferred_name() to get the preferred name for |
| * this module */ |
| |
| char *full_path; /**< full path to the file backing this module */ |
| |
| #ifdef WINDOWS |
| version_number_t file_version; /**< file version number from .rsrc section */ |
| version_number_t product_version; /**< product version number from .rsrc section */ |
| uint checksum; /**< module checksum from the PE headers */ |
| uint timestamp; /**< module timestamp from the PE headers */ |
| size_t module_internal_size; /**< module internal size (from PE headers SizeOfImage) */ |
| #else |
| bool contiguous; /**< whether there are no gaps between segments */ |
| uint num_segments; /**< number of segments */ |
| /** |
| * Array of num_segments entries, one per segment. The array is sorted |
| * by the start address of each segment. |
| */ |
| module_segment_data_t *segments; |
| uint timestamp; /**< Timestamp from ELF Mach-O headers. */ |
| # ifdef MACOS |
| uint current_version; /**< Current version from Mach-O headers. */ |
| uint compatibility_version; /**< Compatibility version from Mach-O headers. */ |
| byte uuid[16]; /**< UUID from Mach-O headers. */ |
| # endif |
| #endif |
| #ifdef AVOID_API_EXPORT |
| /* FIXME: PR 215890: ELF64 size? Anything else? */ |
| /* We can add additional fields to the end without breaking compatibility */ |
| #endif |
| }; |
| |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Looks up the module containing \p pc. If a module containing \p pc is found |
| * returns a module_data_t describing that module. Returns NULL if \p pc is |
| * outside all known modules, which is the case for most dynamically generated |
| * code. Can be used to obtain a module_handle_t for dr_lookup_module_section() |
| * or dr_get_proc_address() via the \p handle field inside module_data_t. |
| * |
| * \note Returned module_data_t must be freed with dr_free_module_data(). |
| */ |
| module_data_t * |
| dr_lookup_module(byte *pc); |
| |
| DR_API |
| /** |
| * Looks up the module with name \p name ignoring case. If an exact name match is found |
| * returns a module_data_t describing that module else returns NULL. User must call |
| * dr_free_module_data() on the returned module_data_t once finished. Can be used to |
| * obtain a module_handle_t for dr_get_proc_address(). |
| * \note Returned module_data_t must be freed with dr_free_module_data(). |
| */ |
| module_data_t * |
| dr_lookup_module_by_name(const char *name); |
| |
| DR_API |
| /** |
| * Looks up module data for the main executable. |
| * \note Returned module_data_t must be freed with dr_free_module_data(). |
| */ |
| module_data_t * |
| dr_get_main_module(void); |
| |
| DR_API |
| /** |
| * Initialize a new module iterator. The returned module iterator contains a snapshot |
| * of the modules loaded at the time it was created. Use dr_module_iterator_hasnext() |
| * and dr_module_iterator_next() to walk the loaded modules. Call |
| * dr_module_iterator_stop() when finished to release the iterator. \note The iterator |
| * does not prevent modules from being loaded or unloaded while the iterator is being |
| * walked. |
| */ |
| dr_module_iterator_t * |
| dr_module_iterator_start(void); |
| |
| DR_API |
| /** |
| * Returns true if there is another loaded module in the iterator. |
| */ |
| bool |
| dr_module_iterator_hasnext(dr_module_iterator_t *mi); |
| |
| DR_API |
| /** |
| * Retrieves the module_data_t for the next loaded module in the iterator. User must call |
| * dr_free_module_data() on the returned module_data_t once finished. |
| * \note Returned module_data_t must be freed with dr_free_module_data(). |
| */ |
| module_data_t * |
| dr_module_iterator_next(dr_module_iterator_t *mi); |
| |
| DR_API |
| /** |
| * User should call this routine to free the module iterator. |
| */ |
| void |
| dr_module_iterator_stop(dr_module_iterator_t *mi); |
| |
| DR_API |
| /** |
| * Makes a copy of \p data. Copy must be freed with dr_free_module_data(). |
| * Useful for making persistent copies of module_data_t's received as part of |
| * image load and unload event callbacks. |
| */ |
| module_data_t * |
| dr_copy_module_data(const module_data_t *data); |
| |
| DR_API |
| /** |
| * Frees a module_data_t returned by dr_module_iterator_next(), dr_lookup_module(), |
| * dr_lookup_module_by_name(), or dr_copy_module_data(). \note Should NOT be used with |
| * a module_data_t obtained as part of a module load or unload event. |
| */ |
| void |
| dr_free_module_data(module_data_t *data); |
| |
| DR_API |
| /** |
| * Returns the preferred name for the module described by \p data from |
| * \p data->module_names. |
| */ |
| const char * |
| dr_module_preferred_name(const module_data_t *data); |
| |
| DR_API |
| /** |
| * Returns whether \p addr is contained inside any segment of the module \p data. |
| * We recommend using this routine rather than checking against the \p start |
| * and \p end fields of \p data, as modules are not always contiguous. |
| */ |
| bool |
| dr_module_contains_addr(const module_data_t *data, app_pc addr); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * Iterator over the list of modules that a given module imports from. Created |
| * by calling dr_module_import_iterator_start() and must be freed by calling |
| * dr_module_import_iterator_stop(). |
| * |
| * \note On Windows, delay-loaded DLLs are not included yet. |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| struct _dr_module_import_iterator_t; |
| typedef struct _dr_module_import_iterator_t dr_module_import_iterator_t; |
| |
| /** |
| * Descriptor used to iterate the symbols imported from a specific module. |
| */ |
| struct _dr_module_import_desc_t; |
| typedef struct _dr_module_import_desc_t dr_module_import_desc_t; |
| |
| /** |
| * Module import data returned from dr_module_import_iterator_next(). |
| * |
| * String fields point into the importing module image. Robust clients should |
| * use DR_TRY_EXCEPT while inspecting the strings in case the module is |
| * partially mapped or the app racily unmaps it. The iterator routines |
| * themselves handle faults by stopping the iteration. |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| typedef struct _dr_module_import_t { |
| /** |
| * Specified name of the imported module or API set. |
| */ |
| const char *modname; |
| |
| /** |
| * Opaque handle that can be passed to dr_symbol_import_iterator_start(). |
| * Valid until the original module is unmapped. |
| */ |
| dr_module_import_desc_t *module_import_desc; |
| } dr_module_import_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Creates a module import iterator. Iterates over the list of modules that a |
| * given module imports from. |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| dr_module_import_iterator_t * |
| dr_module_import_iterator_start(module_handle_t handle); |
| |
| DR_API |
| /** |
| * Returns true if there is another module import in the iterator. |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| bool |
| dr_module_import_iterator_hasnext(dr_module_import_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Advances the passed-in iterator and returns the current module import in the |
| * iterator. The pointer returned is only valid until the next call to |
| * dr_module_import_iterator_next() or dr_module_import_iterator_stop(). |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| dr_module_import_t * |
| dr_module_import_iterator_next(dr_module_import_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Stops import iteration and frees a module import iterator. |
| * |
| * \note ELF does not import directly from other modules. |
| */ |
| void |
| dr_module_import_iterator_stop(dr_module_import_iterator_t *iter); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * Symbol import iterator data type. Can be created by calling |
| * dr_symbol_import_iterator_start() and must be freed by calling |
| * dr_symbol_import_iterator_stop(). |
| */ |
| struct _dr_symbol_import_iterator_t; |
| typedef struct _dr_symbol_import_iterator_t dr_symbol_import_iterator_t; |
| |
| /** |
| * Symbol import data returned from dr_symbol_import_iterator_next(). |
| * |
| * String fields point into the importing module image. Robust clients should |
| * use DR_TRY_EXCEPT while inspecting the strings in case the module is |
| * partially mapped or the app racily unmaps it. |
| */ |
| typedef struct _dr_symbol_import_t { |
| const char *name; /**< Name of imported symbol, if available. */ |
| const char *modname; /**< Preferred name of module (Windows only). */ |
| bool delay_load; /**< This import is delay-loaded (Windows only). */ |
| bool by_ordinal; /**< Import is by ordinal, not name (Windows only). */ |
| ptr_uint_t ordinal; /**< Ordinal value (Windows only). */ |
| /* DR_API EXPORT END */ |
| /* We never ask the client to allocate this struct, so we can go ahead and |
| * add fields here without breaking ABI compat. |
| */ |
| /* DR_API EXPORT BEGIN */ |
| } dr_symbol_import_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Creates an iterator over symbols imported by a module. If \p from_module is |
| * NULL, all imported symbols are yielded, regardless of which module they were |
| * imported from. |
| * |
| * On Windows, from_module is obtained from a \p dr_module_import_t and used to |
| * iterate over all of the imports from a specific module. |
| * |
| * The iterator returned is invalid until after the first call to |
| * dr_symbol_import_iterator_next(). |
| * |
| * \note On Windows, symbols imported from delay-loaded DLLs are not included |
| * yet. |
| */ |
| dr_symbol_import_iterator_t * |
| dr_symbol_import_iterator_start(module_handle_t handle, |
| dr_module_import_desc_t *from_module); |
| |
| DR_API |
| /** |
| * Returns true if there is another imported symbol in the iterator. |
| */ |
| bool |
| dr_symbol_import_iterator_hasnext(dr_symbol_import_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Returns the next imported symbol. The returned pointer is valid until the |
| * next call to dr_symbol_import_iterator_next() or |
| * dr_symbol_import_iterator_stop(). |
| */ |
| dr_symbol_import_t * |
| dr_symbol_import_iterator_next(dr_symbol_import_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Stops symbol import iteration and frees the iterator. |
| */ |
| void |
| dr_symbol_import_iterator_stop(dr_symbol_import_iterator_t *iter); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * Symbol export iterator data type. Can be created by calling |
| * dr_symbol_export_iterator_start() and must be freed by calling |
| * dr_symbol_export_iterator_stop(). |
| */ |
| struct _dr_symbol_export_iterator_t; |
| typedef struct _dr_symbol_export_iterator_t dr_symbol_export_iterator_t; |
| |
| /** |
| * Symbol export data returned from dr_symbol_export_iterator_next(). |
| * |
| * String fields point into the exporting module image. Robust clients should |
| * use DR_TRY_EXCEPT while inspecting the strings in case the module is |
| * partially mapped or the app racily unmaps it. |
| * |
| * On Windows, the address in \p addr may not be inside the exporting module if |
| * it is a forward and has been patched by the loader. In that case, \p forward |
| * will be NULL. |
| */ |
| typedef struct _dr_symbol_export_t { |
| const char *name; /**< Name of exported symbol, if available. */ |
| app_pc addr; /**< Address of the exported symbol. */ |
| const char *forward; /**< Forward name, or NULL if not forwarded (Windows only). */ |
| ptr_uint_t ordinal; /**< Ordinal value (Windows only). */ |
| /** |
| * Whether an indirect code object (see dr_export_info_t). (Linux only). |
| */ |
| bool is_indirect_code; |
| bool is_code; /**< Whether code as opposed to exported data (Linux only). */ |
| /* DR_API EXPORT END */ |
| /* We never ask the client to allocate this struct, so we can go ahead and |
| * add fields here without breaking ABI compat. |
| */ |
| /* DR_API EXPORT BEGIN */ |
| } dr_symbol_export_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Creates an iterator over symbols exported by a module. |
| * The iterator returned is invalid until after the first call to |
| * dr_symbol_export_iterator_next(). |
| * |
| * \note To iterate over all symbols in a module and not just those exported, |
| * use the \ref page_drsyms. |
| */ |
| dr_symbol_export_iterator_t * |
| dr_symbol_export_iterator_start(module_handle_t handle); |
| |
| DR_API |
| /** |
| * Returns true if there is another exported symbol in the iterator. |
| */ |
| bool |
| dr_symbol_export_iterator_hasnext(dr_symbol_export_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Returns the next exported symbol. The returned pointer is valid until the |
| * next call to dr_symbol_export_iterator_next() or |
| * dr_symbol_export_iterator_stop(). |
| */ |
| dr_symbol_export_t * |
| dr_symbol_export_iterator_next(dr_symbol_export_iterator_t *iter); |
| |
| DR_API |
| /** |
| * Stops symbol export iteration and frees the iterator. |
| */ |
| void |
| dr_symbol_export_iterator_stop(dr_symbol_export_iterator_t *iter); |
| |
| /* DR_API EXPORT BEGIN */ |
| #ifdef WINDOWS |
| /* DR_API EXPORT END */ |
| DR_API |
| /** |
| * Returns whether \p pc is within a section within the module in \p section_found and |
| * information about that section in \p section_out. \note Not yet available on Linux. |
| */ |
| bool |
| dr_lookup_module_section(module_handle_t lib, |
| byte *pc, IMAGE_SECTION_HEADER *section_out); |
| |
| /* DR_API EXPORT BEGIN */ |
| #endif /* WINDOWS */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Set whether or not the module referred to by \p handle should be |
| * instrumented. If \p should_instrument is false, code from the module will |
| * not be passed to the basic block event. If traces are enabled, code from the |
| * module will still reach the trace event. Must be called from the module load |
| * event for the module referred to by \p handle. |
| * \return whether successful. |
| * |
| * \warning Turning off instrumentation for modules breaks clients and |
| * extensions, such as drwrap, that expect to see every instruction. |
| */ |
| bool |
| dr_module_set_should_instrument(module_handle_t handle, bool should_instrument); |
| |
| DR_API |
| /** |
| * Return whether code from the module should be instrumented, meaning passed |
| * to the basic block event. |
| */ |
| bool |
| dr_module_should_instrument(module_handle_t handle); |
| |
| DR_API |
| /** |
| * Returns the entry point of the exported function with the given |
| * name in the module with the given base. Returns NULL on failure. |
| * |
| * On Linux, when we say "exported" we mean present in the dynamic |
| * symbol table (.dynsym). Global functions and variables in an |
| * executable (as opposed to a library) are not exported by default. |
| * If an executable is built with the \p -rdynamic flag to \p gcc, its |
| * global symbols will be present in .dynsym and dr_get_proc_address() |
| * will locate them. Otherwise, the drsyms Extension (see \ref |
| * page_drsyms) must be used to locate the symbols. drsyms searches |
| * the debug symbol table (.symtab) in addition to .dynsym. |
| * |
| * \note On Linux this ignores symbol preemption by other modules and only |
| * examines the specified module. |
| * \note On Linux, in order to handle indirect code objects, use |
| * dr_get_proc_address_ex(). |
| */ |
| generic_func_t |
| dr_get_proc_address(module_handle_t lib, const char *name); |
| |
| /* DR_API EXPORT BEGIN */ |
| /** |
| * Data structure used by dr_get_proc_address_ex() to retrieve information |
| * about an exported symbol. |
| */ |
| typedef struct _dr_export_info_t { |
| /** |
| * The entry point of the export as an absolute address located |
| * within the queried module. This address is identical to what |
| * dr_get_proc_address_ex() returns. |
| */ |
| generic_func_t address; |
| /** |
| * Relevant for Linux only. Set to true iff this export is an |
| * indirect code object, which is a new ELF extension allowing |
| * runtime selection of which implementation to use for an |
| * exported symbol. The address of such an export is a function |
| * that takes no arguments and returns the address of the selected |
| * implementation. |
| */ |
| bool is_indirect_code; |
| } dr_export_info_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Returns information in \p info about the symbol \p name exported |
| * by the module \p lib. Returns false if the symbol is not found. |
| * See the information in dr_get_proc_address() about what an |
| * "exported" function is on Linux. |
| * |
| * \note On Linux this ignores symbol preemption by other modules and only |
| * examines the specified module. |
| */ |
| bool |
| dr_get_proc_address_ex(module_handle_t lib, const char *name, |
| dr_export_info_t *info OUT, size_t info_len); |
| |
| |
| /* DR_API EXPORT BEGIN */ |
| /************************************************** |
| * SYSTEM CALL PROCESSING ROUTINES |
| */ |
| |
| /** |
| * Data structure used to obtain or modify the result of an application |
| * system call by dr_syscall_get_result_ex() and dr_syscall_set_result_ex(). |
| */ |
| typedef struct _dr_syscall_result_info_t { |
| /** The caller should set this to the size of the structure. */ |
| size_t size; |
| /** |
| * Indicates whether the system call succeeded or failed. For |
| * dr_syscall_set_result_ex(), this requests that DR set any |
| * additional machine state, if any, used by the particular |
| * plaform that is not part of \p value to indicate success or |
| * failure (e.g., on MacOS the carry flag is used to indicate |
| * success). |
| * |
| * For Windows, the success result from dr_syscall_get_result_ex() |
| * should only be relied upon for ntoskrnl system calls. For |
| * other Windows system calls (such as win32k.sys graphical |
| * (NtGdi) or user (NtUser) system calls), computing success |
| * depends on each particular call semantics and is beyond the |
| * scope of this routine (consider using the "drsyscall" Extension |
| * instead). |
| * |
| * For Mach syscalls on MacOS, the success result from |
| * dr_syscall_get_result_ex() should not be relied upon. |
| * Computing success depends on each particular call semantics and |
| * is beyond the scope of this routine (consider using the |
| * "drsyscall" Extension instead). |
| */ |
| bool succeeded; |
| /** |
| * The raw main value returned by the system call. |
| * See also the \p high field. |
| */ |
| reg_t value; |
| /** |
| * On some platforms (such as MacOS), a 32-bit application's |
| * system call can return a 64-bit value. For such calls, |
| * this field will hold the top 32 bit bits, if requested |
| * by \p use_high. It is up to the caller to know which |
| * system calls have 64-bit return values. System calls that |
| * return only 32-bit values do not clear the upper bits. |
| * Consider using the "drsyscall" Extension in order to obtain |
| * per-system-call semantic information, including return type. |
| */ |
| reg_t high; |
| /** |
| * This should be set by the caller, and only applies to 32-bit |
| * system calls. For dr_syscall_get_result_ex(), this requests |
| * that DR fill in the \p high field. For |
| * dr_syscall_set_result_ex(), this requests that DR set the high |
| * 32 bits of the application-facing result to the value in the \p |
| * high field. |
| */ |
| bool use_high; |
| /** |
| * This should be set by the caller. For dr_syscall_get_result_ex(), |
| * this requests that DR fill in the \p errno_value field. |
| * For dr_syscall_set_result_ex(), this requests that DR set the |
| * \p value to indicate the particular error code in \p errno_value. |
| */ |
| bool use_errno; |
| /** |
| * If requested by \p use_errno, if a system call fails (i.e., \p |
| * succeeded is false) dr_syscall_get_result_ex() will set this |
| * field to the absolute value of the error code returned (i.e., |
| * on Linux, it will be inverted from what the kernel directly |
| * returns, in order to facilitate cross-platform clients that |
| * operate on both Linux and MacOS). For Linux and Macos, when |
| * \p succeeded is true, \p errno_value is set to 0. |
| * |
| * If \p use_errno is set for dr_syscall_set_result_ex(), then |
| * this value will be stored as the system call's return value, |
| * negated if necessary for the underlying platform. In that |
| * case, \p value will be ignored. |
| */ |
| uint errno_value; |
| } dr_syscall_result_info_t; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Usable only from a pre-syscall (dr_register_pre_syscall_event()) |
| * event. Returns the value of system call parameter number \p param_num. |
| * |
| * It is up to the caller to ensure that reading this parameter is |
| * safe: this routine does not know the number of parameters for each |
| * system call, nor does it check whether this might read off the base |
| * of the stack. |
| * |
| * \note On some platforms, notably MacOS, a 32-bit application's |
| * system call can still take a 64-bit parameter (typically on the |
| * stack). In that situation, this routine will consider the 64-bit |
| * parameter to be split into high and low parts, each with its own |
| * parameter number. |
| */ |
| reg_t |
| dr_syscall_get_param(void *drcontext, int param_num); |
| |
| DR_API |
| /** |
| * Usable only from a pre-syscall (dr_register_pre_syscall_event()) |
| * event, or from a post-syscall (dr_register_post_syscall_event()) |
| * event when also using dr_syscall_invoke_another(). Sets the value |
| * of system call parameter number \p param_num to \p new_value. |
| * |
| * It is up to the caller to ensure that writing this parameter is |
| * safe: this routine does not know the number of parameters for each |
| * system call, nor does it check whether this might write beyond the |
| * base of the stack. |
| * |
| * \note On some platforms, notably MacOS, a 32-bit application's |
| * system call can still take a 64-bit parameter (typically on the |
| * stack). In that situation, this routine will consider the 64-bit |
| * parameter to be split into high and low parts, each with its own |
| * parameter number. |
| */ |
| void |
| dr_syscall_set_param(void *drcontext, int param_num, reg_t new_value); |
| |
| DR_API |
| /** |
| * Usable only from a post-syscall (dr_register_post_syscall_event()) |
| * event. Returns the return value of the system call that will be |
| * presented to the application. |
| * |
| * \note On some platforms (such as MacOS), a 32-bit application's |
| * system call can return a 64-bit value. Use dr_syscall_get_result_ex() |
| * to obtain the upper bits in that case. |
| * |
| * \note On some platforms (such as MacOS), whether a system call |
| * succeeded or failed cannot be determined from the main result |
| * value. Use dr_syscall_get_result_ex() to obtain the success result |
| * in such cases. |
| */ |
| reg_t |
| dr_syscall_get_result(void *drcontext); |
| |
| DR_API |
| /** |
| * Usable only from a post-syscall (dr_register_post_syscall_event()) |
| * event. Returns whether it successfully retrieved the results |
| * of the system call into \p info. |
| * |
| * The caller should set the \p size, \p use_high, and \p use_errno fields |
| * of \p info prior to calling this routine. |
| * See the fields of #dr_syscall_result_info_t for details. |
| */ |
| bool |
| dr_syscall_get_result_ex(void *drcontext, dr_syscall_result_info_t *info INOUT); |
| |
| DR_API |
| /** |
| * Usable only from a pre-syscall (dr_register_pre_syscall_event()) or |
| * post-syscall (dr_register_post_syscall_event()) event. |
| * For pre-syscall, should only be used when skipping the system call. |
| * This sets the return value of the system call that the application sees |
| * to \p value. |
| * |
| * \note On MacOS, do not use this function as it fails to set the |
| * carry flag and thus fails to properly indicate whether the system |
| * call succeeded or failed: use dr_syscall_set_result_ex() instead. |
| */ |
| void |
| dr_syscall_set_result(void *drcontext, reg_t value); |
| |
| DR_API |
| /** |
| * Usable only from a pre-syscall (dr_register_pre_syscall_event()) or |
| * post-syscall (dr_register_post_syscall_event()) event. |
| * For pre-syscall, should only be used when skipping the system call. |
| * |
| * This sets the returned results of the system call as specified in |
| * \p info. Returns whether it successfully did so. |
| * See the fields of #dr_syscall_result_info_t for details. |
| */ |
| bool |
| dr_syscall_set_result_ex(void *drcontext, dr_syscall_result_info_t *info); |
| |
| DR_API |
| /** |
| * Usable only from a pre-syscall (dr_register_pre_syscall_event()) |
| * event, or from a post-syscall (dr_register_post_syscall_event()) |
| * event when also using dr_syscall_invoke_another(). Sets the system |
| * call number of the system call about to be invoked to \p new_num. |
| */ |
| void |
| dr_syscall_set_sysnum(void *drcontext, int new_num); |
| |
| DR_API |
| /** |
| * Usable only from a post-syscall (dr_register_post_syscall_event()) |
| * event. An additional system call will be invoked immediately, |
| * using the current values of the parameters, which can be set with |
| * dr_syscall_set_param(). The system call to be invoked should be |
| * specified with dr_syscall_set_sysnum(). |
| * |
| * Use this routine with caution. Especially on Windows, care must be |
| * taken if the application is expected to continue afterward. When |
| * system call parameters are stored on the stack, modifying them can |
| * result in incorrect application behavior, particularly when setting |
| * more parameters than were present in the original system call, |
| * which will result in corruption of the application stack. |
| * |
| * On Windows, when the first system call is interruptible |
| * (alertable), the additional system call may be delayed. |
| * |
| * DR will set key registers such as r10 for 64-bit or xdx for |
| * sysenter or WOW64 system calls. However, DR will not set ecx for |
| * WOW64; that is up to the client. |
| */ |
| void |
| dr_syscall_invoke_another(void *drcontext); |
| |
| #ifdef WINDOWS |
| DR_API |
| /** |
| * Must be invoked from dr_init(). Requests that the named ntoskrnl |
| * system call be intercepted even when threads are native (e.g., due |
| * to #DR_EMIT_GO_NATIVE). Only a limited number of system calls |
| * being intercepted while native are supported. This routine will |
| * fail once that limit is reached. |
| * |
| * @param[in] name The system call name. The name must match an exported |
| * system call wrapper in \p ntdll.dll. |
| * @param[in] sysnum The system call number (the value placed in the eax register). |
| * @param[in] num_args The number of arguments to the system call. |
| * @param[in] wow64_index The value placed in the ecx register when this system |
| * call is executed in a WOW64 process. This value should be obtainable |
| * by examining the system call wrapper. |
| * |
| * \note Windows only. |
| */ |
| bool |
| dr_syscall_intercept_natively(const char *name, int sysnum, int num_args, |
| int wow64_index); |
| #endif |
| |
| /* DR_API EXPORT BEGIN */ |
| /************************************************** |
| * PLATFORM-INDEPENDENT FILE SUPPORT |
| * |
| * Since a FILE cannot be used outside of the DLL it was created in, |
| * we have to use HANDLE on Windows. |
| * We hide the distinction behind the file_t type |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Creates a new directory. Fails if the directory already exists |
| * or if it can't be created. |
| * Relative path support on Windows is identical to that described in dr_open_file(). |
| */ |
| bool |
| dr_create_dir(const char *fname); |
| |
| DR_API |
| /** |
| * Deletes the given directory. Fails if the directory is not empty. |
| * Relative path support on Windows is identical to that described in dr_open_file(). |
| */ |
| bool |
| dr_delete_dir(const char *fname); |
| |
| DR_API |
| /** |
| * Returns the current directory for this process in \p buf. |
| * On Windows, reading the current directory is considered unsafe |
| * except during initialization, as it is stored in user memory and |
| * access is not controlled via any standard synchronization. |
| */ |
| bool |
| dr_get_current_directory(char *buf, size_t bufsz); |
| |
| DR_API |
| /** |
| * Checks for the existence of a directory. |
| * Relative path support on Windows is identical to that described in dr_open_file(). |
| */ |
| bool |
| dr_directory_exists(const char *fname); |
| |
| DR_API |
| /** |
| * Checks the existence of a file. |
| * Relative path support on Windows is identical to that described in dr_open_file(). |
| */ |
| bool |
| dr_file_exists(const char *fname); |
| |
| /* The extra BEGIN END is to get spacing nice. */ |
| /* DR_API EXPORT BEGIN */ |
| /* DR_API EXPORT END */ |
| /* DR_API EXPORT BEGIN */ |
| /* flags for use with dr_open_file() */ |
| /** Open with read access. */ |
| #define DR_FILE_READ 0x1 |
| /** Open with write access, but do not open if the file already exists. */ |
| #define DR_FILE_WRITE_REQUIRE_NEW 0x2 |
| /** |
| * Open with write access. If the file already exists, set the file position to the |
| * end of the file. |
| */ |
| #define DR_FILE_WRITE_APPEND 0x4 |
| /** |
| * Open with write access. If the file already exists, truncate the |
| * file to zero length. |
| */ |
| #define DR_FILE_WRITE_OVERWRITE 0x8 |
| /** |
| * Open with large (>2GB) file support. Only applicable on 32-bit Linux. |
| * \note DR's log files and tracedump files are all created with this flag. |
| */ |
| #define DR_FILE_ALLOW_LARGE 0x10 |
| /** Linux-only. This file will be closed in the child of a fork. */ |
| #define DR_FILE_CLOSE_ON_FORK 0x20 |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Opens the file \p fname. If no such file exists then one is created. |
| * The file access mode is set by the \p mode_flags argument which is drawn from |
| * the DR_FILE_* defines ORed together. Returns INVALID_FILE if unsuccessful. |
| * |
| * On Windows, \p fname is safest as an absolute path (when using Windows system |
| * calls directly there is no such thing as a relative path). A relative path |
| * passed to this routine will be converted to absolute on a best-effort basis |
| * using the current directory that was set at process initialization time. |
| * (The most recently set current directory can be retrieved (albeit with no |
| * safety guarantees) with dr_get_current_directory().) Drive-implied-absolute |
| * paths ("\foo.txt") and other-drive-relative paths ("c:foo.txt") are not |
| * supported. |
| * |
| * On Linux, the file descriptor will be marked as close-on-exec. The |
| * DR_FILE_CLOSE_ON_FORK flag can be used to automatically close a |
| * file on a fork. |
| * |
| * \note No more then one write mode flag can be specified. |
| * |
| * \note On Linux, DR hides files opened by clients from the |
| * application by using file descriptors that are separate from the |
| * application's and preventing the application from closing |
| * client-opened files. |
| */ |
| file_t |
| dr_open_file(const char *fname, uint mode_flags); |
| |
| DR_API |
| /** Closes file \p f. */ |
| void |
| dr_close_file(file_t f); |
| |
| DR_API |
| /** |
| * Renames the file \p src to \p dst, replacing an existing file named \p dst if |
| * \p replace is true. |
| * Atomic if \p src and \p dst are on the same filesystem. |
| * Returns true if successful. |
| */ |
| bool |
| dr_rename_file(const char *src, const char *dst, bool replace); |
| |
| DR_API |
| /** |
| * Deletes the file referred to by \p filename. |
| * Returns true if successful. |
| * On both Linux and Windows, if filename refers to a symlink, the symlink will |
| * be deleted and not the target of the symlink. |
| * On Windows, this will fail to delete any file that was not opened with |
| * FILE_SHARE_DELETE and is still open. |
| * Relative path support on Windows is identical to that described in dr_open_file(). |
| */ |
| bool |
| dr_delete_file(const char *filename); |
| |
| DR_API |
| /** Flushes any buffers for file \p f. */ |
| void |
| dr_flush_file(file_t f); |
| |
| DR_API |
| /** |
| * Writes \p count bytes from \p buf to file \p f. |
| * Returns the actual number written. |
| */ |
| ssize_t |
| dr_write_file(file_t f, const void *buf, size_t count); |
| |
| DR_API |
| /** |
| * Reads up to \p count bytes from file \p f into \p buf. |
| * Returns the actual number read. |
| */ |
| ssize_t |
| dr_read_file(file_t f, void *buf, size_t count); |
| |
| /* NOTE - keep in synch with OS_SEEK_* in os_shared.h and SEEK_* from Linux headers. |
| * The extra BEGIN END is to get spacing nice. Once we have more control over the layout |
| * of the API header files share with os_shared.h. */ |
| /* DR_API EXPORT BEGIN */ |
| /* DR_API EXPORT END */ |
| /* DR_API EXPORT BEGIN */ |
| /* For use with dr_file_seek(), specifies the origin at which to apply the offset. */ |
| #define DR_SEEK_SET 0 /**< start of file */ |
| #define DR_SEEK_CUR 1 /**< current file position */ |
| #define DR_SEEK_END 2 /**< end of file */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Sets the current file position for file \p f to \p offset bytes |
| * from the specified origin, where \p origin is one of the DR_SEEK_* |
| * values. Returns true if successful. |
| */ |
| bool |
| dr_file_seek(file_t f, int64 offset, int origin); |
| |
| DR_API |
| /** |
| * Returns the current position for the file \p f in bytes from the start of the file. |
| * Returns -1 on an error. |
| */ |
| int64 |
| dr_file_tell(file_t f); |
| |
| DR_API |
| /** |
| * Returns a new copy of the file handle \p f. |
| * Returns INVALID_FILE on error. |
| */ |
| file_t |
| dr_dup_file_handle(file_t f); |
| |
| DR_API |
| /** |
| * Determines the size of the file \p fd. |
| * On success, returns the size in \p size. |
| * \return whether successful. |
| */ |
| bool |
| dr_file_size(file_t fd, OUT uint64 *size); |
| |
| /* The extra BEGIN END is to get spacing nice. */ |
| /* DR_API EXPORT BEGIN */ |
| /* DR_API EXPORT END */ |
| /* DR_API EXPORT BEGIN */ |
| /* flags for use with dr_map_file() */ |
| enum { |
| /** |
| * If set, changes to mapped memory are private to the mapping process and |
| * are not reflected in the underlying file. If not set, changes are visible |
| * to other processes that map the same file, and will be propagated |
| * to the file itself. |
| */ |
| DR_MAP_PRIVATE = 0x0001, |
| #ifdef UNIX |
| /** |
| * If set, indicates that the passed-in start address is required rather than a |
| * hint. On Linux, this has the same semantics as mmap with MAP_FIXED: i.e., |
| * any existing mapping in [addr,addr+size) will be unmapped. This flag is not |
| * supported on Windows. |
| */ |
| DR_MAP_FIXED = 0x0002, |
| #endif |
| #ifdef WINDOWS |
| /** |
| * If set, loads the specified file as an executable image, rather than a data |
| * file. This flag is not supported on Linux. |
| */ |
| DR_MAP_IMAGE = 0x0004, |
| #endif |
| /** |
| * If set, loads the specified file at a location that is reachable from |
| * the code cache and client libraries by a 32-bit displacement. If not |
| * set, the mapped file is not guaranteed to be reachable from the cache. |
| */ |
| DR_MAP_CACHE_REACHABLE = 0x0008, |
| }; |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Memory-maps \p size bytes starting at offset \p offs from the file \p f |
| * at address \p addr with privileges \p prot. |
| * |
| * @param[in] f The file to map. |
| * @param[in,out] size The requested size to map. Upon successful return, |
| * contains the actual mapped size. |
| * @param[in] offs The offset within the file at which to start the map. |
| * @param[in] addr The requested start address of the map. Unless \p fixed |
| * is true, this is just a hint and may not be honored. |
| * @param[in] prot The access privileges of the mapping, composed of |
| * the DR_MEMPROT_READ, DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits. |
| * @param[in] flags Optional DR_MAP_* flags. |
| * |
| * \note Mapping image files for execution is not supported. |
| * |
| * \return the start address of the mapping, or NULL if unsuccessful. |
| */ |
| void * |
| dr_map_file(file_t f, INOUT size_t *size, uint64 offs, app_pc addr, uint prot, |
| uint flags); |
| |
| DR_API |
| /** |
| * Unmaps a portion of a file mapping previously created by dr_map_file(). |
| * \return whether successful. |
| * |
| * @param[in] map The base address to be unmapped. Must be page size aligned. |
| * @param[in] size The size to be unmapped. |
| * All pages overlapping with the range are unmapped. |
| * |
| * \note On Windows, the whole file will be unmapped instead. |
| * |
| */ |
| bool |
| dr_unmap_file(void *map, size_t size); |
| |
| /* TODO add copy_file, truncate_file etc. |
| * All should be easy though at some point should perhaps tell people to just use the raw |
| * systemcalls, esp for linux where they're documented and let them provide their own |
| * wrappers. */ |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /************************************************** |
| * PRINTING |
| */ |
| /* DR_API EXPORT END */ |
| |
| DR_API |
| /** |
| * Writes to DR's log file for the thread with drcontext \p drcontext if the current |
| * loglevel is >= \p level and the current \p logmask & \p mask != 0. |
| * The mask constants are below. |
| * Logging is disabled for the release build. |
| * If \p drcontext is NULL, writes to the main log file. |
| */ |
| void |
| dr_log(void *drcontext, uint mask, uint level, const char *fmt, ...); |
| |
| /* hack to get these constants in the right place in dr_ir_api.h */ |
| #if 0 /* now skip a line to prevent gen_api.pl from removing this */ |
| |
| /* DR_API EXPORT BEGIN */ |
| |
| /* The log mask constants */ |
| #define LOG_NONE 0x00000000 /**< Log no data. */ |
| #define LOG_STATS 0x00000001 /**< Log per-thread and global statistics. */ |
| #define LOG_TOP 0x00000002 /**< Log top-level information. */ |
| #define LOG_THREADS 0x00000004 /**< Log data related to threads. */ |
| #define LOG_SYSCALLS 0x00000008 /**< Log data related to system calls. */ |
| #define LOG_ASYNCH 0x00000010 /**< Log data related to signals/callbacks/etc. */ |
| #define LOG_INTERP 0x00000020 /**< Log data related to app interpretation. */ |
| #define LOG_EMIT 0x00000040 /**< Log data related to emitting code. */ |
| #define LOG_LINKS 0x00000080 /**< Log data related to linking code. */ |
| #define LOG_CACHE 0x00000100 /**< Log data related to code cache management. */ |
| #define LOG_FRAGMENT 0x00000200 /**< Log data related to app code fragments. */ |
| #define LOG_DISPATCH 0x00000400 /**< Log data on every context switch dispatch. */ |
| #define LOG_MONITOR 0x00000800 /**< Log data related to trace building. */ |
| #define LOG_HEAP 0x00001000 /**< Log data related to memory management. */ |
| #define LOG_VMAREAS 0x00002000 /**< Log data related to address space regions. */ |
| #define LOG_SYNCH 0x00004000 /**< Log data related to synchronization. */ |
| #define LOG_MEMSTATS 0x00008000 /**< Log data related to memory statistics. */ |